卡顿掉帧主因是@keyframes混入非合成属性(如left、width、box-shadow等)触发重排或重绘,致整段动画退回CPU渲染;仅transform和opacity安全,且需验证图层提升、动态管理will-change。

卡顿掉帧不是因为“没开硬件加速”,而是关键帧里混入了任一非合成属性,整段 @keyframes 就会无声无息退回 CPU 渲染——低端安卓机(尤其 Android 5–7 WebView)一帧内重排多次,主线程直接堵死。
为什么@keyframes里写left或width必卡
改 left 或 width 会强制触发重排(reflow),浏览器得在主线程里重新计算位置、尺寸、换行、文本流……这个过程 CPU 全包。实测一次重排耗时 3–8ms,远超 16.67ms 的 60fps 帧间隔。而 transform: translateX(100px) 只挪图层,由 GPU 合成线程处理,不碰布局、不重绘、不阻塞主线程。
- 错:
@keyframes slide { to { left: 200px; } }→ 整段动画降级回 CPU 渲染 - 对:
@keyframes slide { to { transform: translateX(200px); } }→ 真正走合成管线 - 同一关键帧里同时写
left和transform,浏览器会放弃硬件加速
哪些属性会让@keyframes悄悄掉帧
浏览器不会报错,但只要关键帧里出现一个非合成属性,整段动画就退回 CPU 渲染。常见“隐形杀手”包括:
-
box-shadow:模糊计算强制 CPU 绘制,blur-radius每 +2px,显存占用平方级增长 -
filter: blur():低端 WebView 中几乎必掉帧;filter: drop-shadow()在 Chrome 84+ 可合成,但 iOS Safari 仍支持弱 -
background-color、color、border-radius:触发重绘(repaint),大区域或高 DPI 屏上卡顿明显 -
width/height:改盒模型尺寸,必然重排
安全组合只有两个:transform 和 opacity。其他全删。
立即学习“前端免费学习笔记(深入)”;
为什么写了transform还不流畅
用了 transform 只是“有资格”进合成层,不代表真被提升。是否生成绿色图层(Chrome DevTools → Rendering → Layer Borders),取决于:
- 父容器是否设了
overflow: hidden(会抑制子元素提层) - 是否存在
filter: blur(1px)这类父级样式 - JS 是否在动画中调了
getBoundingClientRect()(强制同步 layout,直接破防) -
transform: translateZ(0)在部分 Android 5.1 WebView 中不稳定,translate3d(0, 0, 0)更可靠
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; }或批量加到列表项上
最常被忽略的一点:你以为关掉了 filter 就安全了,但只要页面里还存在一个未移除的 filter 声明,它就仍在影响图层策略。


















