前端程序员面试必背理论之一:重绘和回流。虽然不清楚在日常开发过程中到底有多少小伙伴用过针对回流的代码优化方案,但是面试阶段这属于是基本功中的基本功了。
浏览器渲染过程
在说重绘和回流之前,需要先大致了解一下浏览器的渲染过程。
- HTML和Css在输出到浏览器上以后,浏览器会对源码进行解析,分别生成DOM树和CSSOM树。
- 浏览器合并DOM和CSSOM生成Render Tree,剔除不需要渲染的元素。
- 根据Render Tree确定每个元素的几何信息,包括大小、位置。(这里就是回流/重排)
- 根据渲染树和回流中得到的几何信息,计算出元素的绝对像素,绘制页面。(这里是重绘)
- 将像素发送给GPU进行渲染。(这里牵扯到使用Css进行GPU加速的内容)
备注部分:
-
生成Render Tree的时候不需要渲染的元素已经被剔除,而不是先生成 Render Tree 后剔除。
-
【剔除不需要渲染的元素】包括style、link、meta、script等,以及使用display隐藏起来的元素。
Ok,知道浏览器渲染规则以后,重绘和回流的概念也就清楚了。
概念
当页面中元素发生位置、大小等几何属性改变时,重新计算元素确切几何属性以及它们如何影响其他元素的布局的阶段就是回流/重排(Reflow)。
当页面中元素已经明确了其几何属性,只需要更新元素的视觉表现,将元素转换为屏幕上实际像素进行渲染的阶段就是重绘(Repaint)。
所以从流程图上也能明确:回流一定导致重绘,而重绘不一定导致回流。
那回流什么时候会发生?
- 页面初始化阶段
- 添加/删除可见元素
- 元素几何属性发生变化(位置、大小、内外边距、边框等)
- 内容发生变化(这里是说会引起几何属性发生变化的内容修改,不会引发几何属性变化的内容修改则不触发回流)
- 浏览器窗口尺寸变化
- js获取元素确切几何属性的时候(offset方法、scroll方法、client方法、getComputedStyle方法等)
注意:基于浏览器对于页面渲染的优化,浏览器会将一系列修改推入队列中,达到阈值后,批量化执行回流操作。但js获取元素几何属性时,浏览器需给出渲染完成的属性,所以需要立即清空队列,渲染页面,然后返回给js确切的几何信息。
那重绘什么时候会发生?
- 回流发生的时候
- 元素通过visibility、opacity修改可见度的时候
- 发生颜色、样式等不会引发元素几何属性修改的变化的时候
优化
虽然我们在业务开发层面很少落地这种程度的优化代码,但是还是希望大家在开发过程中注意一些,尽量减少重绘和回流操作。
- 减少对元素几何属性的操作次数,最好一次性操作多个属性。
let headerDOM = document.getElementById("headerId");
// 错误
headerDOM.style.width = '800px';
headerDOM.style.height = '80px';
headerDOM.style.color = '#fff';
// 正确
headerDOM.style.cssText += 'width:800px;height:80px;color:#fff;';
2. 使用class变化,而非style变化的方式
let navDOM = document.getElementById("navId");
// 错误
navDOM.style.color = '#fff';
navDOM.style.backgroud = '#000';
// 正确
navDOM.className += ' active';
3. 操作前先让元素脱离文档流/display隐藏元素,操作完以后才回归
testDOM.style.display = 'none';
// 其他操作ing...
testDOM.style.display = 'inline-block';
4. Js获取元素几何属性在循环外获取,而不是在循环中反复获取
// 错误
for(let i=0; i<10; i++) {
let headerHight = document.getElementById("headerId").offsetHeight;
testDOM[i].style.height = headerHeight + 'px';
}
参考文献
本文使用 markdown.com.cn 排版