动画应仅触发合成,使用transform和opacity属性,避免left/top等会引发重排重绘的属性;will-change需动态设置并及时清除;控制合成层数量与尺寸,避开JS强制同步布局。

核心是让动画只走合成(composite)这一步,跳过重排(layout)和重绘(paint)。浏览器对 transform 和 opacity 的处理已深度优化,改动时只需挪图层或调透明度,全程由合成线程在 GPU 上完成。
只用能触发合成层的属性做动画
这些属性被浏览器识别为“可合成”,修改时不会打断渲染流水线:
-
transform:优先用
translateX/Y/Z、scale、rotate;避免matrix()等非标准写法 -
opacity:淡入淡出必须用它,别用
visibility或display切换 - 伪 3D 提层(仅老设备兜底):
translateZ(0)、translate3d(0,0,0)、perspective: 1000px
以下属性会整段退化到 CPU 渲染,绝对禁用:left、top、width、height、margin、background-color、box-shadow。混用它们(比如 transition: left, transform 0.3s)会让整个动画回退。
will-change 不是开关,而是提示器
它只是提前告诉浏览器“这个元素马上要动了,请准备图层”,不是一写就加速。静态写在 CSS 里(如 .item { will-change: transform; })极易导致图层爆炸,尤其在长列表中。
立即学习“前端免费学习笔记(深入)”;
- ✅ 正确做法:JS 在
touchstart或mouseenter后 1–2 帧内设el.style.willChange = 'transform' - ✅ 动画结束监听
transitionend后立刻设回'auto' - ❌ 错误做法:全局加、hover 状态长期保留、配合
transition: all
控制合成层数量与尺寸
每个合成层都占显存,过多或过大反而拖慢性能:
- 用 Chrome DevTools → Rendering → ✅ “Layer Borders” 查看实际图层分布
- 避免给每张图片、每个列表项都加
translateZ(0) - 对
filter: blur()这类高开销操作,限制作用区域;必要时降级为box-shadow - 父容器若有
overflow: hidden、filter或opacity < 1,可能压制子元素提层,translate3d就失效
避开 JS 强制同步布局的陷阱
CSS 写得再对,只要动画过程中 JS 做了这些事,就会打断渲染流水线:
- 读取
offsetTop、getBoundingClientRect()、scrollHeight等返回布局信息的属性 - 读写交替(如先读
el.offsetTop,再改el.style.transform) - 在
requestAnimationFrame中混入布局查询
正确做法是:批量读取 → 批量写入;或改用 ResizeObserver、IntersectionObserver 替代频繁 DOM 查询。


















