视差悬停特效:鼠标跟随的沉浸式交互体验

大家好,我是石小石,小册《油猴脚本实战指南》作者。


视差悬停效果

最近在 Trae 官网发现了一个有趣的交互效果:当鼠标悬停在图标上时,图标会根据鼠标的移动产生跟随位移,看起来很炫酷。

于是我用AI问了一下,才知道这种效果叫"视差悬停效果",挺有意思。

视差悬停效果"(Parallax Hover Effect)是一种常见的前端视觉交互效果,模拟景深原理,让页面元素在鼠标移动时产生错位移动,营造出立体或空间感,增强用户交互体验。

用Trae实现一个类似效果

先让Trae帮忙实现一个类似效果:

生成的代码如下:

js 复制代码
<template>
  <!-- 外层容器,负责监听鼠标移动和离开事件 -->
  <div class="logo-container" @mousemove="handleMouseMove" @mouseleave="resetEffect">
    <!-- 中心 Logo 容器,包含所有球体 -->
    <div class="logo" ref="logo">
      <!-- 循环生成球体 -->
      <div
        v-for="(sphere, index) in spheresConfig"
        :key="index"
        class="sphere"
        ref="spheres"
        :style="{
          width: sphere.size + 'px',       // 球体直径
          height: sphere.size + 'px',      // 球体直径
          top: sphere.top,                 // 定位:上边距
          left: sphere.left,               // 定位:左边距
          right: sphere.right,             // 定位:右边距
          bottom: sphere.bottom,           // 定位:下边距
          backgroundColor: sphere.color    // 球体颜色
        }"
      ></div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

// 中心 Logo 元素引用
const logo = ref(null)
// 所有球体元素的引用
const spheres = ref([])

// 球体配置数组
const spheresConfig = [
  { size: 60, top: '40px', left: '40px', color: '#3498db' },
  { size: 60, top: '40px', right: '40px', color: '#e74c3c' },
  { size: 60, bottom: '40px', left: '40px', color: '#2ecc71' },
  { size: 60, bottom: '40px', right: '40px', color: '#f39c12' },
  { size: 70, top: '120px', left: '120px', color: '#9b59b6' },
  { size: 50, top: '70px', left: '170px', color: '#1abc9c' },
  { size: 45, top: '180px', left: '70px', color: '#d35400' },
  { size: 40, top: '150px', right: '60px', color: '#27ae60' },
  { size: 35, top: '210px', right: '120px', color: '#8e44ad' },
  { size: 25, top: '30px', left: '150px', color: '#c0392b' }
]

// 鼠标移动事件
const handleMouseMove = (e) => {
  const container = e.currentTarget
  const rect = container.getBoundingClientRect()

  // 计算鼠标在容器中的相对位置(-1 ~ 1)
  const x = ((e.clientX - rect.left) / rect.width - 0.5) * 2
  const y = ((e.clientY - rect.top) / rect.height - 0.5) * 2

  // 中心 Logo 随鼠标旋转
  logo.value.style.transform = `rotateX(${-y * 20}deg) rotateY(${x * 20}deg)`

  // 每个球体根据鼠标位置做视差位移
  spheres.value.forEach((sphere, index) => {
    const sphereX = x * 35 * Math.cos(index * 0.8) // X 方向位移
    const sphereY = y * 35 * Math.sin(index * 0.8) // Y 方向位移
    const sphereZ = Math.abs(x * y) * 70 + index * 8 // Z 方向位移(层次感)

    sphere.style.transform = `translate3d(${sphereX}px, ${sphereY}px, ${sphereZ}px)`
  })
}

// 鼠标移出时恢复初始位置
const resetEffect = () => {
  logo.value.style.transform = 'rotateX(0) rotateY(0)'
  spheres.value.forEach(sphere => {
    sphere.style.transform = 'translate3d(0, 0, 0)'
  })
}
</script>

<style scoped>
/* 外层容器,定义大小和透视深度 */
.logo-container {
    position: relative;
    width: 300px;
    height: 300px;
    margin: 100px auto;
    perspective: 1200px;
}

/* 中心 Logo 容器 */
.logo {
    width: 100%;
    height: 100%;
    position: relative;
    transform-style: preserve-3d;
    transition: transform 0.1s ease-out;
}

/* 球体公共样式 */
.sphere {
    position: absolute;
    border-radius: 50%;
    transition: transform 0.3s ease-out;
    box-shadow: inset -8px -8px 16px rgb(0 0 0 / 30%), 
        8px 16px rgb(255 255 255 / 30%);
}
</style>

效果还是很不错的:

这个demo的原理其实很简单,主要分为三步:

  1. 获取鼠标相对位置
  2. 模拟相机视角变化
  3. 实现分层错位运动

获取鼠标相对位置

js 复制代码
const rect = container.getBoundingClientRect();
const x = ((e.clientX - rect.left) / rect.width - 0.5) * 2;
const y = ((e.clientY - rect.top) / rect.height - 0.5) * 2;

getBoundingClientRect() 是浏览器 DOM API 中非常常用的方法,用于获取元素相对于视口(viewport)的尺寸和位置。

  • xy 都是范围 -11 的值,中心是 0,代表鼠标在容器里的相对位置。
  • 这个范围让后续计算方便做正负方向运动。

模拟相机视角变化

js 复制代码
logo.value.style.transform = `rotateX(${-y * 20}deg) rotateY(${x * 20}deg)`;

这一步的主要目的是让整体结构跟着鼠标动,模拟相机视角变化。最简单的就是通过CSS的transform实现3D位置变化。

这里的 20 是旋转最大角度,让效果不会太夸张。

分层错位运动

要想让球体有空间感,就要实现球体视差位移,同样的可以使用transform属性。

js 复制代码
spheres.value.forEach((sphere, index) => {
  const sphereX = x * 35 * Math.cos(index * 0.8);
  const sphereY = y * 35 * Math.sin(index * 0.8);
  const sphereZ = Math.abs(x * y) * 70 + index * 8;
  
  sphere.style.transform = `translate3d(${sphereX}px, ${sphereY}px, ${sphereZ}px)`;
});

"视差"的核心是让每个球体产生不同速度和运动方向:

  • 每个球体的 X 轴偏移 sphereX = 鼠标横向偏移 * 35 * 一个和球序号有关的余弦函数。
    → 余弦函数让每个球的偏移方向和幅度有差异,避免动作统一死板。
  • Y 轴偏移 sphereY 类似,用正弦函数产生错落。
  • Z 轴偏移 sphereZ 通过鼠标位置和球的索引控制,让不同球体在"深度"上产生不同位移,制造层次感。
  • translate3d 是 CSS 3D 变换,直接告诉浏览器把球体往三个方向移动。

当然,在鼠标离开时,我们需要所有元素慢慢回到原点,避免停留在中间状态。

ini 复制代码
logo.value.style.transform = 'rotateX(0) rotateY(0)';
spheres.value.forEach(sphere => {
  sphere.style.transform = 'translate3d(0, 0, 0)';
});

开源库

市面上有一些专门做视差或3D交互的库,可以帮我们快速实现效果。

Parallax.js

  • 经典轻量级视差库,支持基于鼠标移动的多层元素视差效果。
  • 用法简单,适合基础悬停视差。
  • GitHub 地址

Vanilla-tilt.js

  • 类似 Tilt.js,功能更全面,支持触摸事件和更多配置。
  • 纯原生 JS,无依赖,性能好。
  • GitHub 地址

react-parallax-tilt (React 生态)

  • React 版本的Tilt效果库,适合 React 项目。
  • 支持自定义视差和旋转,易于集成。
  • GitHub 地址
相关推荐
@PHARAOH9 小时前
HOW - 前端输入场景支持拼音匹配
前端
计算机安禾10 小时前
【c++面向对象编程】第21篇:运算符重载基础:语法、规则与不可重载的运算符
java·前端·c++
__log10 小时前
Vue 3 核心技术深度解析:从“会用API“到“懂原理、能表达“
前端·javascript·vue.js
ZC跨境爬虫10 小时前
跟着 MDN 学 HTML day_52:(深入 XPathExpression 接口)
开发语言·前端·javascript·ui·html·音视频
UXbot11 小时前
AI 原型工具零设计基础操作指南与功能解析(2026)
前端·ui·产品经理·原型模式·web app
yuzhiboyouye11 小时前
VO一般java后端怎么转换成前端想要的数据
java·前端·状态模式
小脑斧12312 小时前
从范式重构到工程落地:OpenTiny NEXT 引领前端智能化新范式
前端·hermesagent·opentiny next
小江的记录本12 小时前
【AI大模型选型指南】《2026年5月(最新版)国内外主流AI大模型选型指南》(企业版)
前端·人工智能·后端·ai作画·aigc·ai编程·ai写作
幽络源小助理12 小时前
最新轻量美化表白墙系统源码v2.0_带后台版_附搭建教程
前端·开源·源码·php源码