如何实现Smooth tracking mouse moves平滑鼠标移动跟踪效果
平滑鼠标移动跟踪效果实现方案
你之前尝试搭配right/bottom属性做延迟导致效果变差的核心原因很明确:left/top和right/bottom属于同一定位体系下的互斥属性,同时赋值会让浏览器在两套定位规则之间做计算拉扯,不仅会触发额外重排,还很容易出现位置偏移、抖动问题,这个实现思路从根上就错了。
目前主流站点(包括你提到的参考站)用的都是逐帧线性插值(Lerp)+ GPU加速渲染的方案,实现出来的平滑效果自然不生硬,性能也足够好,具体实现步骤如下:
核心实现步骤
- 基础样式配置
给跟随鼠标的元素设置固定定位,只保留left: 0; top: 0初始值,完全移除right/bottom相关属性,额外加pointer-events: none避免元素挡住页面交互,建议给元素设置固定宽高方便居中对齐。 - 坐标变量初始化
定义两组坐标,一组存实时鼠标真实位置,一组存跟随元素当前的渲染位置,再配置一个缓动系数控制平滑度:// 鼠标真实坐标 let mouseX = 0, mouseY = 0; // 跟随元素当前渲染坐标 let currentX = 0, currentY = 0; // 缓动系数,取值0-1,数值越小跟手速度越慢、拖影感越强,参考站效果大概在0.15左右 const ease = 0.15; const cursorEl = document.querySelector('.custom-cursor'); - 鼠标位置监听
给window绑定mousemove事件,事件触发时只更新真实鼠标坐标即可,不要在事件回调里直接修改元素位置:window.addEventListener('mousemove', (e) => { // 坐标值减去元素自身宽高的一半,实现元素中心对准鼠标,而不是元素左上角对准鼠标 mouseX = e.clientX - cursorEl.offsetWidth / 2; mouseY = e.clientY - cursorEl.offsetHeight / 2; }); - 逐帧缓动渲染
用requestAnimationFrame绑定浏览器渲染帧率做动画循环,每帧通过线性插值计算元素当前应该移动到的位置,用transform3d赋值触发GPU加速,避免重排卡顿:function rafLoop() { // 每帧让元素向鼠标位置移动剩余距离的ease比例,实现连续平滑的跟手效果 currentX += (mouseX - currentX) * ease; currentY += (mouseY - currentY) * ease; // 用translate3d走合成层渲染,比修改 修改left/top性能高3-5倍 cursorEl.style.transform = `translate3d(${currentX}px, ${currentY}px, 0)`; requestAnimationFrame(rafLoop); } // 启动动画循环 rafLoop();
常见踩坑避坑
- 不要用CSS
transition做平滑效果:快速甩动鼠标时transition会出现明显的拖影断层,手感僵硬,完全不如逐帧插值的连续感 - 不要用
left/top更新元素位置:这两个属性修改会触发整个文档的重排计算,页面元素多的时候很容易掉帧 - 如果要做多图层级的跟随效果(比如外层弱光晕、内层实心点的双层光标),只需要多定义几组current坐标,给不同图层设置不同的ease值即可,比如外层光晕设0.08,内层圆点设0.2,就能做出自然的层次延迟感
调试的时候可以先把ease值调到1,这时候元素会完全跟手无延迟,确认坐标对齐没有偏移之后,再慢慢把ease值往小调找合适的手感,能省很多调试时间。
内容的提问来源于stack exchange,提问作者Juka Chu
相关产品推荐
相关产品推荐

