用top/left动画必卡,因其每帧触发主线程重排,CPU耗时3–8ms超60fps帧间隔;应仅用transform和opacity,配合will-change动态控制及Layers面板验证图层提升。

为什么用 top/left 动画必卡
改 top 或 left 会强制触发重排(reflow),浏览器必须在主线程里重新计算位置、尺寸、换行、文本流……这个过程 CPU 全包。在 Android 5–7 WebView 或 MT6737 等低端芯片上,一次重排耗时常达 3–8ms,远超 16.67ms 的 60fps 帧间隔,动画直接掉到 20fps 以下,手指滑动都“粘滞”。
而 transform: translateX(100px) 只挪图层,由 GPU 合成线程处理,不碰布局、不重绘、不阻塞主线程。
@keyframes 里混了非合成属性就全废
浏览器不会报错,但只要关键帧里出现一个 width、height、box-shadow、filter、background-color 或 border-radius,整段动画就默默退回到 CPU 渲染——哪怕只加了一行 color: #fff;。
- 安全组合只有两个:
transform和opacity - 位移统一用
transform: translate(30px, 20px),不是top/left组合 - 缩放用
scale(),旋转用rotate(),别碰盒模型属性 - 文字颜色渐变别用
color动画,改用两层文字叠一起 +opacity切换
will-change 是定时器,不是保险丝
静态写 .item { will-change: transform; } 等于让浏览器永远给每个元素建独立 GPU 图层。一屏 20 个列表项,低端安卓机极易 OOM 卡死。
- 加的时机:用户交互瞬间(如
touchstart)或requestAnimationFrame第一帧内 - 删的时机:监听
animationend后立刻执行el.style.willChange = 'auto' - iOS Safari 对 ≤16ms 动画可能不触发事件,必须加兜底:
setTimeout(() => el.style.willChange = 'auto', duration + 100) - 绝对不要写
* { will-change: transform; }或批量加到列表项上
怎么确认 GPU 加速真起了作用
写了 transform 不等于就加速了。关键看浏览器是否真建了独立合成层:
立即学习“前端免费学习笔记(深入)”;
- Chrome DevTools → Rendering 面板 → 勾选 “Layer Borders”:有绿色边框才是被提升的图层
- Layers 面板搜索目标元素:应单独显示为
GraphicsLayer,而非 “Shared with ancestor” - 动画过程中禁用所有
getBoundingClientRect()、offsetHeight、getComputedStyle()—— 这些调用会强制同步 layout,直接破防
动画卡顿最常被忽略的点,是 JS 在动画中偷偷读取布局信息;哪怕只是写一行 el.style.width = '100px',也会让合成线程等在那儿,帧率瞬间归零。


















