应仅用transform和opacity做动画,因二者仅触发合成层操作、避开重排与重绘;width、height、top、left、margin、padding、font-size等属性会强制重排,必然卡顿。

直接改 transform 和 opacity,别碰 left、width、margin 这类会强制重排的属性——这是最有效、最易落地的解法。
哪些 CSS 属性一改就触发回流?
只要浏览器需要重新计算元素在页面中的位置或尺寸,就会回流。典型属性包括:
-
width、height、top、left、right、bottom -
margin、padding、border、font-size、line-height -
display(比如从block切到none)、position、float
常见错误现象:在 scroll 或 mousemove 里反复设置 el.style.left = x + 'px',页面立刻卡顿;或循环中读取 offsetHeight,强制浏览器同步计算,把批量优化全废了。
为什么用 transform/opacity 能绕过回流?
因为这两个属性属于「合成层属性」,浏览器默认把它们交给 GPU 单独处理,不参与主渲染流程的布局和绘制阶段。前提是该元素已提升为独立图层(例如已有 transform 值,或显式加了 will-change: transform)。
使用场景很明确:
- 拖拽位移 → 改
transform: translateX(10px),别改left - 缩放动画 → 用
transform: scale(1.2),别调width/height - 淡入淡出 → 用
opacity: 0.3,别切visibility: hidden或display: none - 频繁动画元素可提前加
will-change: transform,但别滥用——它会预分配图层内存,开多了反而拖慢
为什么 class 切换比 style 操作更安全?
直接写 el.style.left = '10px' 会污染内联样式,导致优先级混乱,而且每次赋值都可能触发一次重排;而 class 是声明式的,所有样式收口在 CSS 文件里,浏览器能批量合并、缓存、复用渲染结果。
实操建议:
- 把状态抽成 class,比如
.is-dragging、.is-fading,用el.classList.add()/.remove() - 避免拼接
style.cssText字符串,比如el.style.cssText = 'left:10px;top:20px;' - 需要动态值时,优先用 CSS 自定义属性:
el.style.setProperty('--offset-x', x),再在 CSS 里写transform: translateX(var(--offset-x))
真正容易被忽略的点是:回流不是“单个元素的事”——改一个元素的 width,可能连带触发父容器重排、兄弟节点重排、甚至整行文字折行重算。所以优化不能只盯着动画元素本身,得看它在整个文档流里的“牵连范围”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











