真优化只需用 transform 和 opacity,因二者触发 gpu 合成层,绕过 layout 和 paint;其他属性如 left、width、background-color 等均引发重排重绘或 cpu 渲染。

只用 transform 和 opacity 才算真优化
浏览器对 transform(如 translate、scale、rotate)和 opacity 的过渡,会自动触发合成层(compositing layer),交由 GPU 处理,完全绕过 layout 和 paint 阶段。这是唯一被现代浏览器稳定支持的「零重排+零重绘」路径。
其他看似能动的属性,实际都在 CPU 上硬扛:
-
left、top:改值 → 触发 layout → 重绘 → 掉帧 -
width、height:同上,还可能引发父容器连锁重排 -
margin、padding:layout 开销大,且无法被 GPU 合成 -
background-color:虽不触发布局,但每次变化都要重绘整块区域,滚动中极易卡顿
为什么 transition: all 是性能地雷
transition: all 0.3s 看似省事,实则等于把所有可动画属性都塞进过渡队列——哪怕你只改了 color,浏览器也得检查是否同时动了 font-size 或 border,导致解析开销上升、缓动函数失效、甚至意外触发 layout。
更危险的是:某次 CSS 覆盖或 JS 动态设了 margin,整条过渡就悄悄降级到 CPU 渲染,而你根本看不出样式报错。
正确做法是显式声明:
.btn {
transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.25s ease;
}
确保 JS 或 class 切换时,也只改这两个属性。
合成层不是写了就生效
加了 transform: translateZ(0) 或 will-change: transform 不代表 GPU 加速已启用。关键得看浏览器是否真建了独立图层。
打开 Chrome DevTools → Rendering 面板 → 勾选 “Layer Borders”:
- 有绿色边框 = 成功提层
- 没绿框 = 被抑制:检查父容器是否用了
overflow: hidden、filter: blur(1px)或backdrop-filter - 绿框太小/断续 = 图层被合并:避免在动画元素上同时用动态
box-shadow或filter
will-change 是提示,不是开关。全局写 * { will-change: transform; } 在安卓低端机上可能直接 OOM。
移动端特别容易翻车的点
iOS Safari 对极短动画(≤16ms)可能不触发 transitionend;Android 4.4 WebView 完全忽略 will-change,还可能因强制提层导致闪烁。
生产环境建议:
- JS 控制动画时,提前一帧设
el.style.willChange = 'transform',监听transitionend后立刻清空 - 兜底用
setTimeout(() => el.style.willChange = 'auto', duration + 100) - 旧环境降级用
backface-visibility: hidden替代will-change - 滚动中禁用
background-color过渡——换思路,用opacity+ 半透明遮罩模拟渐变
真正卡顿往往不出现在 transition 写法里,而出现在父容器约束、隐式合成失败、或 JS 强制同步读取 offsetHeight 导致的 layout thrashing 上。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











