swiftwind0405 / blog

my blog within git issues
9 stars 1 forks source link

【浏览器】回流与重绘 #33

Open swiftwind0405 opened 4 years ago

swiftwind0405 commented 4 years ago

reflow(回流/重构)

当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建, 这就称为回流(reflow)。每个页面至少需要一次回流,就是在页面第一次加载的时候。

repaint/redraw(重绘)

当盒子的位置、大小以及其他属性,例如颜色、字体大小等都确定下来之后,浏览器便把这些原色都按照各自的特性绘制一遍,将内容呈现在页面上。重绘是指一个元素外观的改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。 重绘发生在元素的可见的外观被改变,但并没有影响到布局的时候。比如,仅修改DOM元素的字体颜色(只有Repaint,因为不需要调整布局)

何时发生回流重绘

回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流。比如以下情况:

注意:回流一定会触发重绘,而重绘不一定会回流

根据改变的范围和程度,渲染树中或大或小的部分需要重新计算,有些改变会触发整个页面的重排,比如,滚动条出现的时候或者修改了根节点。

回流的优化

对树的局部甚至全局重新生成是非常耗性能的,所以要避免频繁触发回流

浏览器的优化机制

现代的浏览器都是很聪明的,由于每次重绘都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重绘过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。但是!当你获取布局信息的操作的时候,会强制队列刷新,比如当你访问以下属性或者使用以下方法:

具体可以访问这篇文章:what-forces-layout

以上属性和方法都需要返回最新的布局信息,因此浏览器不得不清空队列,触发回流重绘来返回正确的值。因此,我们在修改样式的时候,最好避免使用上面列出的属性,他们都会刷新渲染队列。如果要使用它们,最好将值缓存起来。

开启GPU加速的方法

开启后,会将 dom 元素提升为独立的渲染层,它的变化不会再影响文档流中的布局。

最小化重绘和重排

由于重绘和重排可能代价比较昂贵,因此最好就是可以减少它的发生次数。为了减少发生次数,我们可以合并多次对DOM和样式的修改,然后一次处理掉。

参考资料