Web Animations API自定义光标:duration与easing不生效问题求助
问题原因
每次触发mousemove时,你都会创建一个全新的动画实例,浏览器会立即终止之前未完成的动画。更关键的是,新动画的起始状态默认使用元素的基础CSS样式值(比如初始的transform: none),而非上一个动画中断时的当前位置。这就导致光标看起来直接跳到目标点,完全忽略了你设置的duration和easing参数。
另外,你只定义了单个关键帧(目标状态),Web Animations API会默认用元素的基础样式作为起始帧,但当动画被频繁中断时,这个默认行为会破坏平滑过渡的逻辑。
解决方案
要实现平滑的光标跟随动画,你需要:
- 跟踪当前正在运行的动画,每次触发
mousemove时先终止旧动画; - 以光标当前的实际位置作为新动画的起始帧,而非基础样式值;
- 确保动画结束后保留最终状态,避免回到初始位置。
修改后的代码如下:
const CURSOR = document.querySelector("#cursor"); let currentAnimation = null; window.addEventListener("mousemove", (e) => { // 终止之前未完成的动画 if (currentAnimation) { currentAnimation.cancel(); } // 获取光标当前的transform值作为动画起始状态 const computedTransform = getComputedStyle(CURSOR).transform; const startTransform = computedTransform === 'none' ? 'translate3d(0, 0, 0) translate(-50%, -50%)' : computedTransform; // 创建从当前位置到目标位置的动画 currentAnimation = CURSOR.animate( [ { transform: startTransform }, { transform: `translate3d(${e.clientX}px, ${e.clientY}px, 0) translate(-50%, -50%)` } ], { duration: 4000, easing: "linear", fill: "forwards" // 动画结束后保留最终状态 } ); // 动画正常完成时提交样式到基础样式(可选,增强兼容性) currentAnimation.onfinish = () => { currentAnimation.commitStyles(); currentAnimation = null; }; });
#cursor { position: fixed; top: 0px; left: 0px; height: 16px; width: 16px; border-radius: 50%; background-color: black; will-change: transform; }
<div id="cursor"></div>
关键修改说明
- 跟踪当前动画:用
currentAnimation变量保存正在运行的动画实例,每次触发mousemove时先调用cancel()终止旧动画,避免多个动画冲突。 - 动态设置起始帧:通过
getComputedStyle获取光标当前的实际transform值,作为新动画的起始关键帧,确保平滑过渡的连续性。 - 保留动画状态:添加
fill: "forwards"配置,让动画结束后将最终状态应用到元素上;配合onfinish事件中的commitStyles(),确保样式被持久化到元素的基础CSS中,避免浏览器自动移除填充动画导致状态回退。
如果使用top/left替代transform,逻辑完全一致:只需获取当前的top和left计算值作为起始帧,再定义目标位置的top/left即可。
内容的提问来源于stack exchange,提问作者Abhijeet Singh
相关产品推荐
相关产品推荐

