requestAnimationFrame 实现暂停/恢复需手动管理时间戳:暂停时保存 lastTime 和 elapsed,恢复时用新帧时间减暂停起始时间补时长;CSS 的 animation-play-state 仅适用于纯 CSS 动画,对 Canvas/WebGL/Three.js/SVG 无效;Three.js 需同时调用 clock.stop() 和 renderer.setAnimationLoop(null);Canvas 动画暂停须冻结 velocity 等状态变量并限帧防瞬移。

用 requestAnimationFrame 实现暂停/恢复必须自己管理时间戳
HTML5 本身没有内置的「暂停动画」API,requestAnimationFrame 一旦调用就会持续触发,靠 cancelAnimationFrame 只能终止,不能暂停。真正实现暂停/恢复,关键在于:**跳过帧计算,但保留上一帧的时间状态**。
常见错误是直接停掉 requestAnimationFrame 再重启——这会导致动画从头开始或出现跳变,因为时间差被重置了。
- 记录进入暂停时的
lastTime和当前elapsed - 恢复时用新帧时间减去暂停起始时间,补上“被跳过的时长”
- 避免在暂停期间仍调用
requestAnimationFrame(哪怕什么也不做)
animation-play-state 只对 CSS 动画有效,对 Canvas/WebGL 无效
如果你用的是 @keyframes + animation 的纯 CSS 动画,animation-play-state: paused 是最简方案,支持直接写在元素 style 或 class 中:
element.style.animationPlayState = 'paused'; element.style.animationPlayState = 'running';
但它对以下情况完全不起作用:
立即学习“前端免费学习笔记(深入)”;
-
中用requestAnimationFrame手绘的动画 - WebGL 渲染循环(如 Three.js 的
renderer.setAnimationLoop) - SVG
元素(需用beginElement()/endElement()控制)
Three.js 中暂停动画要停渲染循环,而非仅停 clock
Three.js 的 Clock.getDelta() 可以暂停,但如果不同时停掉 renderer.setAnimationLoop,场景仍会不断重绘,CPU 白耗、电池白掉。
正确做法是双控:
- 调用
clock.stop()阻止时间推进 - 用
renderer.setAnimationLoop(null)彻底停掉渲染循环 - 恢复时先
clock.start(),再重新传入渲染函数给setAnimationLoop
注意:clock.elapsedTime 在 stop() 后不再更新,但值仍保留,可直接用于插值计算。
Canvas 动画暂停后恢复容易丢帧或卡顿
Canvas 动画若依赖 deltaTime 做物理模拟(比如速度 × 时间),暂停期间若没冻结所有状态变量,恢复瞬间可能因累积 delta 过大导致对象瞬移或穿模。
建议在暂停时显式冻结关键状态:
- 保存并冻结
velocity、acceleration、rotationSpeed等运动变量 - 不依赖全局
performance.now()差值,改用相对暂停点的偏移量 - 恢复时不直接加“暂停时长”,而是用
Math.min(delta, 16)限帧,防止单帧过载
复杂动画的状态分散在多个对象中时,最容易漏冻某个 isMoving 标志位,结果看起来“暂停了但还在动”。











