现代Web动画应优先使用requestAnimationFrame和element.animate(),因二者可精准对齐渲染节奏、支持暂停/反向/进度控制;setTimeout/setInterval易卡顿、掉帧、无法感知页面可见性。

Web动画用 JavaScript 实现,核心不在于“有多少方法”,而在于「哪些方法真正可控、可中断、能精准对齐渲染节奏」。直接上结论:现代开发中只应优先考虑 requestAnimationFrame 和 CSS 动画 + element.animate(),其余如 setTimeout 或 setInterval 驱动的动画在真实项目里基本是退路,不是首选。
为什么不用 setTimeout 或 setInterval 做动画
它们和浏览器刷新节奏完全脱节,容易卡顿、掉帧、时间漂移。比如设成 16ms 触发一次,但 JS 执行阻塞或主线程繁忙时,实际间隔可能变成 30ms 甚至更久,动画就“一卡一卡”的。
- 无法感知页面是否被隐藏(
setTimeout在后台标签页仍会执行,浪费资源) - 手动计算 easing 逻辑容易出错,且每帧都要重算位置/透明度等属性,性能差
- 暂停、回放、反向播放需自己维护状态机,极易漏掉边界情况(如动画中途 DOM 被移除)
requestAnimationFrame 是怎么工作的
它把回调函数交给浏览器,在下一次重绘前执行——也就是说,你写的动画逻辑天然对齐 60fps(或设备当前刷新率),且在页面不可见时自动暂停。
- 必须在回调内再次调用自身才能形成循环:
function animate() { /* 更新样式 */ requestAnimationFrame(animate); } - 不要在里面做 heavy work(如遍历大数组、触发强制同步布局),否则会拖慢帧率
- 想控制动画进度?自己存一个
startTime和elapsed,用performance.now()算经过时间,再套 easing 函数
element.animate() 和 CSS 动画哪个更合适
element.animate() 是 Web Animations API 的一部分,比纯 CSS 动画灵活得多,尤其适合需要运行时动态生成、暂停、调节速度或链式组合的场景。
立即学习“Java免费学习笔记(深入)”;
- CSS 动画写死在样式表里,修改
duration或delay得靠 class 切换或 JS 操作style.animationDuration,麻烦且难追踪 -
element.animate()返回一个Animation对象,可直接调用.pause()、.reverse()、.currentTime = 1000精确跳转 - 注意兼容性:
element.animate()在 Safari 上直到 iOS 17.4 / macOS 14.4 才支持完整的 fill modes 和 iteration composite;老版本需降级到 CSS +getAnimations()
动画卡顿最常被忽略的三个点
哪怕用了 requestAnimationFrame 或 element.animate(),动画依然卡,大概率栽在这三处:
- 读取了触发 layout 的属性,比如
offsetTop、clientWidth、getComputedStyle(el).height—— 这会强制浏览器同步计算样式和布局,打断渲染流水线 - 在动画帧里频繁操作
innerHTML或增删节点,引发重排重绘 - 没用
will-change: transform或transform: translateZ(0)提前告诉浏览器这个元素要动,导致某些属性(如left/top)触发昂贵的 paint
真正难的不是让东西动起来,而是让动得稳、停得准、切得顺——尤其是跨组件、跨路由、响应式尺寸变化时,动画状态管理比动画本身更费神。











