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

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


视差悬停效果

最近在 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 地址
相关推荐
一枚前端小能手1 分钟前
🆘 Git翻车现场救援指南:5个救命技巧让你起死回生
前端·git
快起来别睡了6 分钟前
Web Worker:前端性能优化的“幕后英雄”
前端
雾岛听风来6 分钟前
MySQL事务原理:从ACID到隔离级别的全解析
前端
豆包MarsCode15 分钟前
TRAE Rules 实践:为项目配置 6A 工作流
trae
三小河18 分钟前
借用数组非破坏性方法来优化react的状态更新
前端
海拥26 分钟前
AI编程实践:使用Trae快速开发“躲避陨石”HTML小游戏
前端·trae
tanxiaomi41 分钟前
✨ 基于 JsonSerialize 实现接口返回数据的智能枚举转换(优雅告别前端硬编码!)
java·前端·spring·spring cloud·mybatis
好好好明天会更好43 分钟前
vue中template的使用
前端·html
快起来别睡了1 小时前
虚拟滚动:前端长列表性能优化的“魔法”
前端
XiongLiding1 小时前
12KB 的 Excel 导出库 sheetex 是怎么来的
前端