什么是重绘和回流

html-css032

什么是重绘和回流,第1张

在HTML中,每个元素都可以理解成一个盒子,在浏览器解析过程中,会涉及到回流与重绘。

回流 :布局引擎会根据各种样式计算每个盒子在页面上的大小与位置。

在页面初始渲染阶段,回流不可避免的触发,可以理解成页面一开始是空白的元素,后面添加了新的元素使页面布局发生改变。

当渲染树的一部分因为元素的规模尺寸、布局、隐藏等改变需要重新构建的操作,会影响布局的操作。

重绘 :当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制。

当渲染树的一些元素只需更新属性,而这些属性只会影响元素的外观,而不影响布局的操作。浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式,这里就仅仅触发了重绘。

回流 触发时机

任何会改变元素几何信息(元素的位置和尺寸大小)的操作,都会触发回流。

1)添加或者删除可见的 DOM 元素;

2)元素的位置发生变化,元素尺寸改变(边距、填充、边框、宽度和高度);

3)内容变化。比如文本变化(用户在 input 框中输入文字)、图片被另一个不同尺寸的图片所替代;

4)浏览器窗口尺寸改变。如resize事件发生时。

5)获取一些特定属性的值。offsetTop、offsetLeft、

offsetWidth、offsetHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、clientTop、clientLeft、clientWidth、clientHeigh。这些属性有一个共性,就是需要通过即时计算得到。因此浏览器为了获取这些值,也会进行回流。

6)当你修改网页的默认字体时。

常见的回流:

重绘 触发时机

回流必定会发生重绘,重绘不一定会引发回流。

常见的重绘:

1)使用 transform 替代 top

2)不要把节点的属性值放在一个循环里当成循环里的变量。

3)避免使用 table 布局,可能table 中每个元素的大小以及内容的改动会造成整个 table 的重新布局。

4)对于那些复杂的动画,对其设置 position: fixed/absolute,尽可能地使元素脱离文档流,从而减少对其他元素的影响

5)把 DOM 离线后修改。如:使用 documentFragment 对象在内存里操作 DOM。我们还可以通过通过设置元素属性display: none,将其从页面上去掉,然后再进行后续操作,这些后续操作也不会触发回流与重绘,这个过程称为离线操作。

6)如果想设定元素的样式,通过改变元素的 class 类名。不要一条一条地修改 DOM 的样式。与其这样,还不如预先定义好 css 的 class,然后修改 DOM 的 className。

--end--

1.1 重绘

重绘是指页面中某些元素发生了不影响布局的变化时(如颜色改变),浏览器重新绘制的过程。此时由于只需要UI层面的重新像素绘制,因此损耗较少。 仅仅 引发重绘的操作如下所示(注意:回流必定触发重绘,但是重绘不一定触发回流):

1)改变背景色;

2)改变文字颜色;

3)改变边框颜色;

通过visibility:hidden隐藏元素;

……

1.2 回流

回流是指页面中某些元素发生变化而影响了布局时(如尺寸、位置改变),浏览器需要重新布局并绘制的过程。引发回流的操作如下所示:

1)页面初次渲染;

2)浏览器窗口大小改变;

3)元素尺寸、位置、内容发生改变;

4)元素字体大小变化;

5)添加或者删除可见的 dom 元素;

5)激活 CSS 伪类(例如::hover);

6)查询某些属性或调用某些方法:

clientWidth、clientHeight、clientTop、clientLeft

offsetWidth、offsetHeight、offsetTop、offsetLeft

scrollWidth、scrollHeight、scrollTop、scrollLeft

getComputedStyle() :Window.getComputedStyle()方法返回一个对象,该对象在应用活动样式表并解析这些值可能包含的任何基本计算后报告元素的所有CSS属性的值。

getBoundingClientRect()

scrollTo():scrollTo() 方法可把内容滚动到指定的坐标。

1.3 减少回流和重绘

1.3.1 浏览器自身优化策略

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

offsetTop、offsetLeft、offsetWidth、offsetHeight

scrollTop、scrollLeft、scrollWidth、scrollHeight

clientTop、clientLeft、clientWidth、clientHeight

getComputedStyle()

getBoundingClientRect

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

另一优化就是浏览器认为position为absolute或fixed的元素更改只会影响其本身和子元素,而static的元素变化则会影响之后的所有元素。原因在于absolute和fixed认为元素从文档流中清除了,怎么操作是内部的事。例如:对于复杂动画效果,使用绝对定位让其脱离文档流

1.3.2 多次操作变为一次操作

不要一条一条的修改DOM的样式,尽量使用class进行样式修改。

把DOM离线修改(批量修改DOM)

1)使用documentFragment对象在内存里操作DOM

2)先把DOM给display:none,修改完毕再显示出来

3)clone一个DOM节点到内存里,然后想怎么改就怎么改,改完后,和在线的那个的交换一下。

1.3.3 其它

使用css3硬件加速,可以让transform、opacity、filters(滤镜)这些动画不会引起回流重绘(注意:对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能)

不要把DOM结点的属性值放在一个循环里当成循环里的变量。不然这会导致大量地读写这个结点的属性。

千万不要使用table布局。因为可能很小的一个小改动会造成整个table的重新布局。