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