transition 必须写在默认状态而非 :hover 中,以确保 js 更新 css 变量时 transform 平滑过渡;transform 是唯一推荐属性,避免 top/left 触发重排;calc() 中不可混用单位,需用 *1px 强制转换或 js 预计算;优先使用 clientx/clienty 并监听 document.documentelement;伪元素 + pointer-events: none 最轻量;注意缩放校准与 touch-action: none。

transition 必须写在默认状态,不能放在 :hover 里
鼠标跟随效果本身靠 JS 更新 CSS 变量实现,但如果你希望元素在跟随过程中带缓动(比如“滞后跟随”或“柔顺入场”),就得用 transition 控制 transform 的变化节奏。常见错误是把 transition 写在 :hover 里——它只在悬停开始时生效,离开时直接跳变,且无法作用于 JS 触发的变量变更。
正确做法是把 transition: transform 0.2s ease-out 直接写在元素的常规样式中。这样只要 transform 值改变(无论是 hover 还是 JS 更新 var(--x)),都会平滑过渡。
-
transform是唯一推荐用于跟随动画的属性,top/left会触发重排,卡顿明显 - 别写
transition: all 0.2s—— 它会过渡box-shadow、outline等无关属性,导致意外抖动 - 如果元素同时响应 hover 和鼠标坐标,
transition会统一作用于两者,无需重复定义
calc() 里不能混用单位,px 和 % 不能直接运算
很多开发者想用 transform: translate(calc(var(--x) - 50%), calc(var(--y) - 50%)) 实现光标居中,结果发现完全不生效。浏览器控制台报 Invalid property value,因为 var(--x) 是字符串(如 "123px"),而 50% 是百分比,CSS 不允许跨单位计算。
解决方法只有两种:
- JS 传入已计算好的像素值:比如元素宽高各 40px,就设
--x为e.clientX - 20 + 'px',CSS 里直接用transform: translate(var(--x), var(--y)) - 或统一用无单位数值 +
* 1px强制转换单位:transform: translate(calc(var(--mouse-x, 0) * 1px), calc(var(--mouse-y, 0) * 1px))
后者更灵活,适合需要动态调整偏移的场景,但 * 1px 缺一不可,否则 calc() 返回 NaN。
滚动时 clientX/clientY 更可靠,pageX/pageY 容易漂移
监听 mousemove 时,用 e.clientX/e.clientY 能保证坐标始终相对于当前视口左上角,页面滚动不影响定位。而 pageX/pageY 是文档级坐标,若没手动减去 window.scrollX/window.scrollY,滚动后光斑就会向下/向右持续偏移。
除非你明确需要文档坐标(比如固定定位到某段文字锚点),否则一律优先用 clientX/clientY。它们天然适配缩放、滚动和移动端 viewport 缩放,兼容性更好。
- 不要监听
body,改用document.documentElement或目标容器,避免 iOS Safari 滚动丢事件 - 如果跟随区域是某个可滚动容器(非全屏),必须用
getBoundingClientRect()计算相对坐标,再更新变量 - 移动端要额外监听
touchmove,取e.touches[0].clientX,并加{ passive: false }防止preventDefault()失效
伪元素 + pointer-events: none 是最轻量的实现路径
用 ::before 或 ::after 渲染跟随元素,比插入真实 DOM 节点更高效。但必须显式设置 content: "" 和 pointer-events: none,否则伪元素会拦截后续点击、悬停事件,导致按钮失灵或 mouseleave 不触发。
定位方式推荐 position: fixed(脱离文档流,不受滚动影响),配合 transform 移动。如果父容器有 transform、perspective 或 filter,fixed 会被截断,此时改用 position: absolute 并确保父级 position: relative。
- 伪元素尺寸建议固定(如
width: 20px; height: 20px),避免内容浮动导致定位基准偏移 - 别在全局通配符(如
* { transform: ... })里引用鼠标变量,会拖慢整个页面合成层 - 真机调试时若发现光斑跳变,大概率是
touch-action: none没加,系统手势干扰了 touch 坐标采样
实际项目中最容易被忽略的,是容器缩放(transform: scale())对像素坐标的放大效应——JS 读到的 clientX 是屏幕像素,而 CSS 中 transform: translate() 的单位是 CSS 像素,两者在缩放后不再一一对应。这时候得用 getComputedStyle(el).transform 解析缩放系数,再做除法校准。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











