必须仅用transform和opacity做动画,因二者不触发布局计算、仅走合成层;width、height、top、left、margin、padding、font-size、display等属性任一变化都会强制重排。

直接用 transform 和 opacity 做动画,其他属性一动就重排——这不是“建议”,是浏览器渲染流水线的硬性规则。
哪些CSS属性会强制触发Reflow?
只要动画中修改了以下任一属性,浏览器就必须执行重排(Layout),无法跳过:
-
width/height:尺寸变化影响流式布局和兄弟元素位置 -
top/left/right/bottom:定位偏移需重新计算文档流坐标 -
margin/padding/border:盒模型参数变更,布局树必须重算 -
font-size/line-height:文本尺寸变化可能引起换行、父容器高度连锁反应 -
display(如display: none↔block):元素进出布局树,整棵子树重排
注意:opacity 和 transform 是例外,但前提是“没混用”——哪怕关键帧里只写了一次 left: 0,整个动画就降级为 CPU 渲染,重排照常发生。
Chrome DevTools 怎么确认是否真发生了Reflow?
别信直觉,看真实数据才是唯一可靠方式:
立即学习“前端免费学习笔记(深入)”;
- 打开 DevTools → More Tools → Layers:如果动画元素没出现在独立图层列表里,说明它没被提升,大概率在走重排路径
- Performance 面板 → 点录制 → 播放动画 → 停止 → 展开 Bottom-Up 视图 → 搜索
Layout:耗时 >1ms 就值得警惕;若Layout占比超过 15%,基本可判定是重排拖慢了帧率 - 别只盯着
Recalculate Style或Paint:重绘开销小,重排才是性能杀手
如何真正避免Reflow做CSS动画?
核心不是“怎么写得更优雅”,而是“怎么让浏览器跳过 Layout 阶段”:
- 只用
transform(translateX、scale、rotate)和opacity,其他属性一律禁用 - 确保元素已提升为独立合成层:可用
transform: translate3d(0, 0, 0)或动画开始前临时设will-change: transform(结束后立刻设回auto,否则吃内存) - 避免父容器有
filter、clip-path或非 identity 的transform:这些会压制子元素的 GPU 加速,强制合并在一层绘制 - 用 class 切换代替内联 style 修改:例如
el.classList.add('is-moving'),而不是el.style.left = '10px'—— 后者每次赋值都可能触发一次重排 - 需要动态值时,优先用 CSS Custom Properties:
element.style.setProperty('--tx', '20px'),再在 CSS 里写transform: translateX(var(--tx))
为什么transition和animation性能差异不大?
性能瓶颈不在于语法是 transition 还是 @keyframes,而在于你改的是什么属性:
- 写
transition: width 0.3s和animation: widen 0.3s,效果一样卡——因为都触发了重排 - 写
transition: transform 0.3s和animation: slide 0.3s,效果一样顺——因为都走合成层 - 错误示范:
transition: left 0.3s, opacity 0.3s—— 只要left在,opacity的优化就白搭
最常被忽略的一点:动画本身不会“自动”升层,也未必默认 GPU 加速。是否重排,只取决于你动了哪个属性、它是否被浏览器识别为合成属性、以及上下文是否破坏了合成条件。


















