requestAnimationFrame能匹配高刷屏,是因为浏览器在每次VSync前主动调用其回调,自动适配120Hz(约8.3ms)或60Hz(约16.7ms)等实际刷新率,无需硬编码;而setTimeout无法对齐VSync,易跳帧且后台不暂停。

高帧率屏幕(如 120Hz、144Hz)本身不“需要”特定 HTML 函数工具——requestAnimationFrame 是唯一与刷新率同步的原生调度机制,其他所谓“函数工具”都是包装或误称。
为什么只有 requestAnimationFrame 能匹配高刷屏
它不是靠你传参数控制帧率,而是浏览器在每次 VSync 前主动调用回调,自动适配当前设备实际刷新率。120Hz 下每帧约 8.3ms,60Hz 下约 16.7ms,完全无需硬编码时间间隔。
- 用
setTimeout(fn, 16)模拟 60fps:系统负载高时回调堆积或延迟,直接跳帧;在 120Hz 屏上仍按 16ms 跑,实际只有 ~30fps -
requestAnimationFrame在后台标签页自动暂停,省电且不干扰主线程 - 必须在回调末尾再次调用自身,否则动画只执行一帧:
function animate() { /* ... */ requestAnimationFrame(animate); }
Canvas 动画在高刷屏上掉帧的常见原因
不是 requestAnimationFrame 不行,而是绘图逻辑拖慢了每帧耗时。高刷屏对单帧预算更严苛(120Hz ≈ 8.3ms/帧),稍超就丢帧。
- 每帧反复读取
offsetTop、getBoundingClientRect()等触发强制同步布局(layout thrashing) - 未用
ctx.scale(dpr, dpr)或未按window.devicePixelRatio设置 canvas 缓冲区尺寸,导致重采样模糊+额外计算 - 图像未预加载完成就调用
drawImage(),造成帧内阻塞或空白 - 在回调中做大量 DOM 插入、class 切换等可能触发重排的操作
哪些 CSS 属性能保住高刷动画不掉帧
哪怕用了 requestAnimationFrame,如果动画属性触发布局(layout)或绘制(paint),依然会卡。真正安全的只有走合成层(compositor)的属性:
立即学习“前端免费学习笔记(深入)”;
- 仅用
transform(含translate、scale、rotate)和opacity—— 它们不触发 layout 和 paint,由 GPU 直接合成 - 避免
left/top、width/height、margin等会强制重排的属性 -
transform: translate(10px, 5px)比分开写translateX+translateY更稳妥,减少样式计算开销 - 旧版 Safari 对
transform: scale(1)可能不启用硬件加速,可改用scale(1.0001)
真正容易被忽略的是:高刷屏下,人眼对卡顿更敏感,但问题根源往往不在“帧率设置”,而在每帧里做了什么。一个 getComputedStyle 调用、一次未缓存的 DOM 查询、甚至一个没防抖的 resize 监听器,都可能让 120Hz 变成幻觉。



















