回流与重绘
浏览器的渲染过程
- 浏览器请求到静态资源后,开始加载并解析。
- 解析HTML文档,构建DOM树。DOM树里包含了所有的HTML标签,包括display:none;隐藏,还有用JS动态添加的元素等。
- 解析CSS属性,构建cssDom树。
- 将DOM树和cssDom树合并后,生成render树。render树不包含隐藏的节点(比如display:none;的节点,还有head节点),因为这些节点不会用于呈现,也不会影响呈现。
- Reflow(回流):在render树的基础上进行布局, 计算每个节点的大小和位置。
- Repaint(重绘):根据渲染树以及回流得到的几何信息,把每个节点绘制在屏幕上。
什么是回流
当render树中的一部分元素的规模尺寸,布局,隐藏等改变而需要重新构建,这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。在回流的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成回流后,浏览器会重新绘制受到影响的部分到屏幕中,此过程叫重绘。因此回流必然会引起重绘。
什么是重绘
当render树中的一些元素的某些属性发生改变时,而这些属性只是影响元素的外观,风格,而不会影响布局,比如background-color。这就称为重绘(repaint)。重绘不一定会引起回流。
区别
回流必将引起重绘,而重绘不一定会引起回流。
比如:只有颜色改变的时候就只会发生重绘而不会引起回流,而当页面布局和几何属性改变时就需要回流。display:none 会触发 reflow,而 visibility:hidden 只会触发 repaint,因为没有发生位置变化。
所以我们能得知回流的成本要高于重绘,回流的花销跟render树有多少节点需要重新构建有关系。
下面这些原因会引起浏览器的回流:
调整窗口大小,改变字体大小,CSS伪类激活(在用户交互过程中发生),添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变等。
调整窗口大小,改变字体大小,CSS伪类激活(在用户交互过程中发生),添加或者删除可见的DOM元素,元素位置改变,元素尺寸改变——边距、填充、边框、宽度和高度,内容改变等。
如何减少回流和重绘
1.浏览器中的优化机制
浏览器会维护一个队列,队列中存放的是会触发回流和重绘的操作,当队列中的操作达到一定阀值或者到了一定的时间间隔时,浏览器就会清空队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。但是!当你获取元素大小和位置等布局信息的时候,比如当你访问offsetTop、scrollTop、clientTop这些属性或者使用getComputedStyle()、getBoundingClientRect()等方法的时候,为了保证准确(得到最新的布局信息),队列会被强制清空,触发回流重绘来返回正确的值。因此,要注意这一类操作的使用!如果要使用它们,最好将值缓存起来。
2.自己进行优化
核心在于减少Repaint和Reflow的次数
Repaint和Reflow是不可避免的,只能说对性能的影响减到最小,给出下面几条建议:
- 改变样式的时候,避免逐条更改样式,而是集中修改样式,例如操作className或使用cssText。
- 避免频繁读取元素几何属性(例如scrollTop)。
- 使用定位让元素脱离文档流。
- 开启css3硬件加速。
- 可以通过批量修改dom元素的方式达到减少回流和重绘的目的,具体有以下三种方式:
- 在设置display:none;的元素上操作,最后显示出来
- 使用文档片段(document fragment),在当前DOM外构建一个子树,在它上面应用所有DOM操作,再把它拷贝回文档。
- 将原始元素拷贝到一个脱离文档的节点中,修改节点后,再替换原始的元素。

浙公网安备 33010602011771号