重排(Reflow)与重绘(Repaint)
改布局触发重排(必连带重绘);只改外观只触发重绘;读布局属性会强制立即重排。
一、对比速查
| 重排(Reflow) | 重绘(Repaint) | |
|---|---|---|
| 定义 | 几何布局变了,浏览器重新算位置和大小 | 外观变了、布局不变,浏览器只重画像素 |
| 开销 | 🔴 大 | 🟡 小 |
| 触发属性 | width height margin padding top left border font-size line-height |
color background border-color opacity visibility box-shadow outline |
| 关系 | 重排 一定连带 重绘 | 重绘 不一定 触发重排 |
二、触发时机详解
触发重排的 3 类操作
① DOM 结构变化
增删可见节点、改文本内容、改层级(z-index 不影响布局不算)
② 几何属性变化
css
width / height margin / padding
top / left border / border-width
font-size line-height
display position
③ 读取布局属性(强制同步重排 --- 最坑)
读以下属性时浏览器必须清空队列、立即执行重排:
| 属性族 | 具体属性 |
|---|---|
| offset | offsetTop offsetLeft offsetWidth offsetHeight |
| scroll | scrollTop scrollLeft scrollWidth scrollHeight |
| client | clientTop clientLeft clientWidth clientHeight |
| 方法 | getBoundingClientRect() getComputedStyle() |
④ 窗口 resize
浏览器窗口大小改变,全局重排。
触发重绘的操作
所有只改变外观、不影响布局的 CSS 属性:
css
color / background* / border-color / outline
opacity / visibility
box-shadow / text-shadow
三、浏览器优化:队列化机制
正常改样式时,浏览器会把多次 DOM 操作放进队列,攒一批再一起重排/重绘,减少次数。
但一旦读取布局属性(offset/scroll/client 族),浏览器必须立刻清空队列、立即重排才能给出准确值。这就是「强制同步布局」(Forced Synchronous Layout)------打断优化的主要原因。
四、代码示例
js
// ✅ 只触发重绘
box.style.backgroundColor = 'blue';
box.style.opacity = 0.5;
// ⚠️ 触发重排 + 重绘
box.style.width = '200px';
box.style.left = '10px';
// ❌ 读布局 → 强制立即重排(典型坑)
console.log(box.offsetWidth);
常见反模式 vs 优化
js
// ❌ 读写交错的强制同步布局
box.style.width = '200px'; // 写入队列
const w = box.offsetWidth; // 强制重排!
box.style.height = w + 'px'; // 再次写入
// ✅ 先批量读,再批量写
const w = box.offsetWidth; // 读
const h = box.offsetHeight; // 读
box.style.width = '200px'; // 写
box.style.height = h + 'px'; // 写(一次重排搞定)
五、一句话速记
重排 = 布局动了(位置/大小)→ 开销大;重绘 = 样子变了(颜色/透明)→ 开销小;读 offset/scroll/client 族属性 → 强制立即重排。