requestAnimationFrame:实现更流畅的前端动画
requestAnimationFrame:实现更流畅的前端动画
浏览器需要不断执行 JavaScript、计算样式、布局页面并绘制画面。常见设备的刷新率是 60Hz,也就是一帧大约只有 16.67ms。如果某一帧的工作时间太长,动画就会出现卡顿。
以前写简单动画时,比较容易想到 setInterval 或 setTimeout。但它们的执行时间和浏览器绘制时机并不一定同步,回调可能在一帧的中间或末尾执行,最终造成丢帧。
requestAnimationFrame 会在浏览器准备绘制下一帧之前调用回调,更适合实现连续动画。
一个简单的动画示例
下面的代码让元素在一秒内向右移动 300 像素:
const box = document.querySelector('.box') |
浏览器会把当前时间传给回调函数,我们可以根据开始时间计算动画进度,而不是假设每次回调之间间隔完全相同。
为什么不直接使用定时器
setTimeout 和 setInterval 只能表示“过一段时间执行”,并不能保证回调正好发生在浏览器绘制之前。当页面比较忙时,定时器还可能被延迟执行。
requestAnimationFrame 的优势主要有两点:
- 与浏览器刷新节奏同步
- 页面不在当前标签页时,浏览器通常会暂停或降低调用频率,减少不必要的计算
减少布局和重绘成本
动画本身流畅,还需要注意修改的 CSS 属性。通常可以优先使用 transform 和 opacity,避免频繁修改会触发布局的属性,例如宽度、高度和部分位置属性。
.box { |
如果只是简单的位移、缩放或透明度变化,CSS 动画通常已经足够;需要根据实时数据计算运动轨迹时,再考虑使用 requestAnimationFrame。
动画优化的目标不是把所有逻辑都塞进 requestAnimationFrame,而是让每一帧做的事情足够少,并且和浏览器的绘制节奏配合起来。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 仰望星空时!
评论
