下面是 第 19 题:浏览器重排(Reflow)与重绘(Repaint)
依旧保持:详细版 + 高频考点 + 优化方案 + 速记卡片
✅ 第 19 题:什么是重排(Reflow)和重绘(Repaint)?有什么区别?如何减少?
这是大型项目必考题。
📘 一、浏览器渲染流程(理解重排重绘的前置)
渲染一个页面,浏览器会依次执行:
- HTML → DOM 树
- CSS → CSSOM 树
- DOM + CSSOM → Render Tree 渲染树
- Layout(排版) → 计算元素的几何位置与大小
- Paint(绘制) → 填充颜色、边框、阴影等
- Composite(合成层) → GPU 合成图层
Reflow / Repaint 就发生在这个过程中。
📘 二、重排(Reflow,布局)
🧠 定义:
改变元素的几何属性(位置 / 大小 / 布局)时,会触发重排。
重排非常昂贵,因为会影响 渲染树布局。
会触发重排的操作:
-
width / height
-
padding / margin
-
display: none → block
-
position (top/left)
-
字体大小变化
-
添加或删除 DOM
-
获取布局信息:
- offsetWidth / offsetHeight
- getComputedStyle
- scrollTop / clientHeight
这些查询会强制浏览器同步布局,也叫 layout thrashing(布局抖动) 。
📘 三、重绘(Repaint,绘制)
🧠 定义:
只改变视觉但不改变布局,会触发重绘。
例如:
- background-color
- color
- visibility (不影响布局)
- outline
- box-shadow
重绘比重排便宜得多。
📘 四、二者关系
- 重排必然会引发重绘
- 重绘不一定会重排
📘 五、如何减少 Reflow / Repaint(面试必背方案)?
🚀 1. CSS:避免逐条写内联样式
❌ 多次写 style
✔️ 合并修改
ini
// BAD
div.style.width = "100px"
div.style.height = "100px"
div.style.padding = "10px"
// GOOD
div.style.cssText = "width:100px;height:100px;padding:10px"
🚀 2. 批量操作 DOM:使用 DocumentFragment
css
const frag = document.createDocumentFragment()
for (let i = 0; i < 1000; i++) {
frag.appendChild(document.createElement('li'))
}
ul.appendChild(frag)
减少 1000 次重排 → 变成 1 次。
🚀 3. 读写分离(非常重要)
❌ 读布局 → 写布局 → 读布局 → 写布局
会导致布局抖动
✔️ 先读,再写
arduino
const height = div.offsetHeight // 读
div.style.height = height + 10 + "px" // 写
🚀 4. 使用 classList 一次性更改多个属性
csharp
div.classList.add("active")
🚀 5. Offscreen 技术:将元素脱离文档流
方法包括:
display: none(重排一次)position: absolute/ fixed- 移动到屏幕外
- 使用
visibility: hidden(重绘,避开重排)
🚀 6. 使用 GPU 加速(transform / opacity)
改变 transform、opacity 不触发布局,也不触发绘制
→ 只发生 合成(Composite) → 最高性能
例如:
css
transform: translateX(10px);
opacity: 0.5;
动画使用 transform + opacity 是最佳实践。
📘 六、速记卡片(10 秒记忆版)
diff
重排 Reflow:改变布局,最昂贵
重绘 Repaint:改变外观,不改变布局
重排 > 重绘 > 合成层 (耗时从大到小)
减少重排:
- 合并 DOM 操作(DocumentFragment)
- 读写分离(避免布局抖动)
- 用 class 操作样式,不逐条写
- 脱离文档流(absolute / display:none)
- 优先使用 transform、opacity 做动画
第 20 题:浏览器从输入 URL 到页面渲染全过程(超高频、大厂必考)