在认识重绘和回流之前,我们先认识一下一个页面加载的时候,会发生什么?
页面加载时,生成一个DOM树,DOM Tree里包含了构成页面所有的标签。Style Sheets(CSS样式表)会生成一个Style Rules。当DOM Tree和Style Rules一起构建出了Render Tree,对于Render Tree的理解:Render Tree和DOM Tree类似,但是Render Tree能够识别样式,在Render Tree上,每一个node(节点)都有自己的Style(样式),但隐藏的节点或是不会用于显示的部分不会包含在Render Tree上。
上图是一个页面在浏览器中渲染(Webkit)的过程。其中的Layout就是布局,页面第一次被加载时或是当Render Tree改变需要重新布局时,就产生了回流(reflow)/重排(relayout)。当Render Tree中的一部分(或全部)的node(节点)因为元素的规模尺寸、布局方式、显示隐藏等改变,浏览器为了重新渲染部分或整个页面,重新计算页面元素位置和几何结构的过程,也就是重新构造渲染树 ,这个过程叫做回流(reflow)/重排(relayout)。每个页面至少发生一次回流/重排,就是页面第一次被加载时。当页面中的元素只是外观或风格被改变不影响布局,比如更换背景色background-color,这个过程就是重绘。
回流/重排(Reflow):当渲染树的一部分必须更新并且节点的尺寸发生了变化,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。
重绘(Repaint):是在一个元素的外观被改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。比如改变某个元素的背景色、文字颜色、边框颜色等等
影响回流(reflow)/重排(relayout)的因素 | 影响重绘(replaint)的因素 |
---|---|
元素的布局和几何属性改变时就会触发reflow。1.页面初始渲染;2.添加/删除可见DOM元素;3.改变元素位置 ----- 定位属性及浮动(position,float);4.改变元素尺寸(宽、高、内外边距、边框等) ----- 盒子模型相关属性(height ,padding ,margin , display ,border-width ,min-height);5.改变元素内容(文本或图片等)(text-align , line-height ,vertival-align ,overflow , font-size,font-family,font-weight);6.改变窗口尺寸;7.获取元素的offsetWidth、offsetHeight、clientWidth、clientHeight、width、height、scrollTop、scrollHeight,请求了getComputedStyle(), 或者 IE的 currentStyle | 页面中的元素更新外观或风格相关的属性时就会触发重绘,如:background,color,visibility, border-style ,border-radius outline-color,cursor,text-decoration, box-shadow |
重绘不一定需要重排(比如颜色的改变),重排必然导致重绘(比如改变网页位置)。
优化:
重绘和重排对我们的浏览器性能有一定的个影响,浏览器会维护1个队列,把所有会引起重排,重绘的操作放入这个队列,等队列中的操作到一定数量或者到了一定时间间隔,浏览器就会flush队列,进行一批处理,这样多次重排,重绘变成一次重排重绘
减少 reflow/repaint:
(1)不要一条一条地修改 DOM 的样式。可以先定义好 css 的 class,然后修改 DOM 的 className。
(2)不要把 DOM 结点的属性值放在一个循环里当成循环里的变量。
(3)为动画的 HTML 元件使用 fixed 或 absoult 的 position,那么修改他们的 CSS 是不会 reflow 的。
(4)千万不要使用 table 布局。因为可能很小的一个小改动会造成整个 table 的重新布局。(table及其内部元素除外,它可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。这也是为什么我们要避免使用table做布局的一个原因。)
(5)不要在布局信息改变的时候做查询(会导致渲染队列强制刷新)