前几天内推某街,被问到了酱紫一个问题,了解浏览器的重绘与重排吗?瞬间蒙住了,的确好像没有怎么听说过。于是今天抽了点时间研究了下重排和重绘,这里分享给大家。
浏览器在页面渲染过程中非常重要的两个概念,即重排和重绘。了解这两个概念对于你在今后写代码过程中,尤其是对性能要求比较高的话,有非常大的帮助。来看看这两个概念:
- 重排(reflow) - 浏览器构建渲染树完成时不包含位置和大小信息。计算元素位置和其他几何信息的过程称为重绘。
- 重绘(repaint) - 当布局结束后,浏览器遍历呈现树,调用呈现器的paint方法,将呈现器的内容显示在屏幕上。
浏览器从服务器端取到文档到呈现到页面过程中是个相对比较复杂的过程,其中重要的就是重绘和重排。粗略的来讲,文档初次加载的时候,浏览器引擎会将HTML文档解析成对应的DOM树,紧接着会根据DOM元素的几何属性来构建一个用于渲染的的渲染树,渲染树的每个节点都包含其大小和内外边距等属性(对于隐藏的不需要显示的元素,不会构建到渲染树当中)。渲染树构建完成后,浏览器就可以将元素放置到正确位置了,再根据渲染树节点的样式属性绘制到页面当中。
更改元素的外观属性但是不影响到其布局的时候会引起重绘,例如修改其可见属性、修改其背景颜色和图片等。与重绘不同的是,更改元素的属性影响到其几何布局的时候就会引起重排,例如修改文字大小、修改内外边距等。对于浏览器来说,这两种情况都会影响到性能,重排影响更大,因为重排会影响到其父元素、子元素和兄弟元素的重排,而且重排是影响性能非常关键的几个因素之一。
既然重排如此影响性能,那么我们来找出来都是哪些改变能引起重排。
- 重新调整浏览器窗口大小
- 修改字体
- 添加、删除样式表
- 修改页面元素内容
- 激活CSS伪类,如a:hover
- 修改class的属性
- 修改DOM
- 计算offsetWidth和offsetHeight
- 设置style的属性
如何避免重排或者减少重排带来的性能问题。
- 修改元素的class属性,并且尽可能在DOM树中比较低的节点上
- 避免在内联样式中设置多重属性
- 将动画应用在absolute定位或者fixed的元素上
- 减少table布局
- 避免使用CSS表达式
元素重排会影响到其所有的子元素,也会影响到其父元素和兄弟元素,因此修改元素的属性会影响到重排的时候,尽可能的在一些DOM树中比较低的节点上修改。这样将其重排的影响范围降到最低。
我们都知道与DOM进行交互会非常影响性能,因此避免过多的进行DOM交互。同样,我们设置样式的时候,避免在内联样式中设置多重属性,因为每设置一个属性都会引起元素的重排,从而极大地影响性能。在需要设置多重属性的时候,我们可以把它封装成一个对象或者完整的class,然后一次性应用到元素当中去。从而将其对性能的影响降到最低。
将动画应用到fixed或者absolute的元素上,因为这不会影响到其他元素的布局,也就不会影响到其他元素的重排和重绘。因为他们只会引起自己的重排和重绘,因此极大地降低了对性能的损耗。
尽量减少table布局。过去为了对齐等原因,大部分的网页都用table布局,但是性能都非常差。table布局的重排和重绘,它可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。而且随便一个cell的高度宽度的修改都会影响到整个表格重排,因此性能非常差。所以,尽量避免使用table布局。
减少使用CSS表达式,因为每当文档重新加载或者部分文档重新加载的时候,CSS表达式都会重新计算一次,因此其性能会收到非常大的影响。
参考:浏览器的重绘与重排
REFLOWS & REPAINTS: CSS PERFORMANCE MAKING YOUR JAVASCRIPT SLOW?