要用 transform + mousemove 实现鼠标悬停视差,监听 mousemove 或 touchmove,归一化计算坐标后用 translate3d 动态偏移背景容器,禁用 background-attachment: fixed。

不能用 background-attachment: fixed 实现“随鼠标滚动”的视差——它只响应页面滚动,不响应鼠标移动。你要的是鼠标悬停时背景偏移的视差效果,核心是 transform + mousemove,不是滚动事件。
为什么 background-attachment: fixed 不管用
这个 CSS 属性只让背景图相对于视口固定,当页面滚动时“看起来不动”,但它完全不感知鼠标位置。你想要的是鼠标在容器内移动时,背景图实时微调位置,属于交互式视差(hover parallax),和滚动视差(scroll parallax)是两回事。
-
background-attachment: fixed触发的是 layout → paint 流程,性能差,移动端基本失效 - 它无法读取
event.clientX/event.clientY,也就没法做归一化偏移计算 - 即使强行用
background-position动态改值,帧率通常卡在 30fps 以下,肉眼可见拖影
用 transform + mousemove 实现 hover 视差
监听容器的 mousemove,计算鼠标相对容器左上角的归一化坐标(-0.5 ~ 0.5),再乘以最大偏移量(如 20px),最后用 transform: translate3d() 更新背景图容器的位置。
- 必须用
getBoundingClientRect()获取容器真实尺寸,避免用offsetWidth或clientWidth(可能含 padding/border) - 偏移量公式:
(e.clientX - rect.left) / rect.width - 0.5,结果范围是 -0.5 ~ 0.5 - 别直接写
element.style.transform = `translate3d(${x}px, ${y}px, 0)`—— 改成变量缓存 +requestAnimationFrame统一更新 - 给背景容器加
will-change: transform(仅需在 hover 期间动态添加,离开时移除)
移动端 touchmove 替代方案
iOS Safari 和部分 Android 浏览器里,mousemove 在非可点击元素上根本不会触发。必须 fallback 到 touchmove,且要处理默认行为冲突。
- 监听
touchmove时,先调用e.preventDefault()阻止页面滚动(否则手指滑动会优先滚动页面) - 从
e.touches[0]取坐标,逻辑和mousemove一致 - 建议加一个开关:检测是否为触屏设备(
'ontouchstart' in window),再绑定对应事件 - 如果容器本身需要滚动(比如内部有长内容),就别用这个视差——它和 scroll 冲突,体验极差
容易被忽略的细节:overflow 和 background-size
偏移后背景图边缘可能被裁掉,尤其当容器设了 overflow: hidden。这不是 bug,是预期行为,但常被误认为失效。
- 确保背景图尺寸 ≥ 容器尺寸 × (1 + 偏移系数),例如偏移 ±20px,容器宽高 800×600,图至少要 840×640
- 用
background-size: cover比contain更安全,但注意它会拉伸裁剪,得提前测试构图重点区域 - 别用
background-position: center—— 它和transform叠加会导致定位错乱,背景容器自身应设background-position: 0 0,靠 transform 移动 - 多个视差层?不同层用不同缩放系数(如背景层 ×0.1,中景层 ×0.3),但都走同一套
mousemove+transform逻辑
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











