直接改类名比逐个改样式更高效,因浏览器会批量flush渲染队列;读布局前若已修改样式,会强制回流。常见触发回流操作包括读取offsetTop等、修改宽高边距、增删DOM、resize/scroll及table改动。

直接改样式不如改类名,读布局信息前别顺手改 DOM,否则浏览器被迫“当场重算”——这不是玄学,是渲染队列被你打断了。
哪些操作会强制触发回流
只要浏览器需要重新计算元素的几何信息(位置、尺寸、是否可见),就会回流。常见动作包括:
- 读取
offsetTop、offsetWidth、getComputedStyle()等布局相关属性时,若此前有未 flush 的样式修改,浏览器会立刻 layout - 修改
width、height、padding、margin、display、font-size - 添加/删除可见 DOM 节点,或调用
appendChild()、removeChild() - 窗口 resize、滚动(尤其监听
scroll时没节流) -
table元素任意改动——哪怕只改一个单元格边框,整表可能重排
为什么集中写样式比逐个赋值更高效
浏览器有个“渲染队列”机制:它会把一批样式写入操作暂存,等 JS 执行完再批量 flush。但一旦你在写样式中间插一句读取布局的代码,队列就被迫提前执行,导致多次回流。
错误示范:
el.style.width = '200px'; el.style.height = '100px'; console.log(el.offsetHeight); // 触发一次回流 el.style.background = 'red'; // 又触发一次回流(因上一步已 flush)
正确做法是读写分离 + 批量写入:
// 先读完所有需要的值
const h = el.offsetHeight;
const w = el.offsetWidth;
// 再一次性改样式
el.className = 'card-active';
// 或用 CSSOM 批量设置
Object.assign(el.style, {
width: '200px',
height: '100px',
background: 'red'
});
display: none 和 visibility: hidden 的区别不只是“看不看得见”
这是最容易被忽略的性能开关:
-
display: none:元素彻底脱离渲染树,对它做任何 DOM 操作(增删子节点、改 class、设 style)都不会触发回流重绘 -
visibility: hidden:元素仍在渲染树中,只是不绘制;改它的color或background仍会触发重绘 - 所以批量操作前,先
el.style.display = 'none',操作完再切回来,比反复触发 layout 更快
动画场景下 requestAnimationFrame 不是银弹
很多人以为用了 requestAnimationFrame 就自动优化了,其实不然:
- 如果每一帧都读
offsetLeft再改transform,依然会每帧回流 - 真正高效的做法是:只读一次布局(比如初始位置),后续用
transform或opacity动画——它们走合成层,不触发布局计算 - 避免在 rAF 回调里调用
getBoundingClientRect()或scrollIntoView()
最常被漏掉的一点:CSS 中用 will-change: transform 提前声明动画属性,能让浏览器早做图层提升,避免动画中突然升层带来的卡顿。但这不是万能药,滥用反而增加内存开销。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











