1. 浏览器渲染流程
要理解回流和重绘,首先需要了解浏览器的渲染流程:
- 解析HTML:构建DOM树
- 解析CSS:构建CSSOM树
- 合并DOM和CSSOM:形成渲染树(Render Tree)
- 布局(Layout):计算每个节点的几何信息(位置、大小)
- 绘制(Paint):将渲染树绘制到屏幕上
2. 回流(Reflow)
定义
回流也称为布局(Layout),是指浏览器重新计算元素的位置和几何属性,导致渲染树的一部分或全部需要重新构建的过程。
触发条件
以下操作会触发回流:
- 页面首次渲染
- 浏览器窗口大小改变
- 元素尺寸、位置、内容发生变化
- 添加或删除可见的DOM元素
- 激活CSS伪类(如:hover)
- 查询某些属性或调用某些方法(如offsetWidth、getComputedStyle等)
常见触发回流的属性和方法
// 几何属性
element.offsetTop
element.offsetLeft
element.offsetWidth
element.offsetHeight
element.scrollTop
element.scrollLeft
element.scrollWidth
element.scrollHeight
element.clientTop
element.clientLeft
element.clientWidth
element.clientHeight
// 方法
element.getBoundingClientRect()
window.getComputedStyle()
3. 重绘(Repaint)
定义
重绘是指当元素的外观发生变化但不影响布局时,浏览器只需要重新绘制受影响的部分到屏幕上的过程。
触发条件
改变以下样式属性通常会触发重绘但不一定触发回流:
- 颜色相关:color, background-color, border-color等
- 透明度:opacity
- 文本相关:text-decoration, text-shadow等
- 可见性:visibility(注意与display:none的区别)
- 轮廓:outline
4. 回流与重绘的关系
- 回流必定引起重绘:当元素发生回流时,其外观通常会受到影响,因此浏览器需要重绘。
- 重绘不一定引起回流:如果只是改变不影响布局的外观属性,则只发生重绘。
5. 性能影响
- 回流比重绘代价更高:回流涉及几何计算,可能影响多个元素。
- 现代浏览器的优化:浏览器会批量处理回流操作,但频繁访问布局属性会强制刷新队列。
6. 优化策略
减少回流次数
-
集中改变样式:
// 不好 element.style.width = '100px'; element.style.height = '200px'; // 好 - 使用cssText或class element.style.cssText = 'width:100px; height:200px;'; // 或 element.className = 'new-class'; -
使用文档片段(DocumentFragment):
const fragment = document.createDocumentFragment(); // 添加多个元素到fragment document.body.appendChild(fragment); -
批量DOM操作:
// 先使元素脱离文档流 const el = document.getElementById('my-element'); el.style.display = 'none'; // 进行多次DOM操作 el.style.display = 'block'; -
避免频繁读取布局属性:
// 不好 - 强制刷新布局队列 const width = element.offsetWidth; element.style.width = width + 10 + 'px'; const height = element.offsetHeight; element.style.height = height + 10 + 'px'; // 好 - 先读取后写入 const width = element.offsetWidth; const height = element.offsetHeight; element.style.width = width + 10 + 'px'; element.style.height = height + 10 + 'px'; -
使用CSS3 transform和opacity:
- 这些属性由GPU处理,不会触发回流重绘
-
避免table布局:
- table中一个小改动可能导致整个table回流
-
使用will-change:
.element { will-change: transform; }提前告诉浏览器哪些属性会变化
-
使用position: absolute 、fixed:
减少对其他元素的影响
7. 现代浏览器优化
现代浏览器采用"增量回流"和"异步回流"策略:
- 维护一个"脏位系统"标记需要回流的元素
- 有一个回流队列,批量处理回流
- 但某些操作(如获取布局属性)会强制刷新队列
8. 工具检测
可以使用浏览器开发者工具检测回流和重绘:
- Chrome DevTools → Performance面板 → 录制性能
- 查看"Layout"(回流)和"Paint"(重绘)事件