一、什么是重排(回流)Reflow和重绘Repaint
1.重排(回流)
重排(回流):当渲染 render 树中的一部分或者全部因为大小边距、布局等问题发生改变而需要 DOM 树重新计算的过程,每个页面至少需要一次重排,就是在页面第一次加载的时候。
2.重绘
当元素的一部分属性发生改变,如外观、背景、颜色等不会引起布局变化,只需要浏览器根据元素的新属性重新绘制,使元素呈现新的外观叫做重绘。
3.页面渲染过程
浏览器加载,解析,渲染页面,分为五个步骤:
1. 浏览器将获取的 HTML 文档解析成 DOM 树;
2. 处理 CSS 标记,构成层叠样式表模型(CSSOM);
3. 将 DOM 和 CSSOM 合并为渲染树(render tree);
4. 渲染树的每个元素的内容(如:节点的几何信息(位置,大小))都是计算过的,称之为 布局layout;
5. 将渲染树上的各个节点绘制到屏幕上,称之为 重绘painting;
painting 时(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素,将 render Tree 光栅化绘制,以便填充为图层。
Display将像素发送给GPU,展示在页面上。(GPU会将多个合成层合并为同一个层,并展示在页面中。而css3硬件加速的原理则是新建合成层)组合这些图层便是性能优化中的关键。
浏览器下载完页面中的所有组件——HTML标记、JavaScript、CSS、图片之后会解析生成两个内部数据结构——DOM树和渲染 render 树。
DOM树表示页面结构,渲染树表示DOM节点如何显示。DOM树中的每一个需要显示的节点在渲染树种至少存在一个对应的节点(隐藏的DOM元素 disply值为none 在渲染树中没有对应的节点)。渲染树中的节点被称为“帧”或“盒”,符合CSS模型的定义,理解页面元素为一个具有填充边距、边框和位置的盒子。一旦 DOM和渲染树构建完成,浏览器就开始显示(绘制)页面元素。
当DOM的变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性,同样其他元素的几何属性和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为重排。完成重排后,浏览器会重新绘制受影响的部分到屏幕,该过程称为重绘。
所以说,第四步(重新生成布局)+ 第五步(重新绘制)是最耗时的部分,这两步合起来,就是我们通常所说的渲染。
网页生成的时候,至少会渲染一次。
在用户访问的过程中,还会不断重新渲染。
重新渲染需要重复之前的第四步(重排)+ 第五步(重绘)或者只有第五个步(重绘)。
也就是说,重绘不一定需要重排(比如颜色的改变),重排必然导致重绘(比如改变网页位置)
二、引起重排(回流)Reflow和重绘Repaint 的属性
1.引起重排的情况
很显然,每次重排,必然会导致重绘,那么,重排会在哪些情况下发生?
页面初始化的时候;
操作DOM时,如添加或者删除可见的DOM元素;
元素位置改变;
元素的尺寸改变——边距、填充、边框、宽度和高度;
元素内容改变;(例如:一个文本被另一个不同尺寸的图片替代,用户在input框中输入文字)
浏览器窗口尺寸改变——resize事件发生时;
计算 offsetWidth 和 offsetHeight 属性;
设置 style 属性;
改变文字大小;
添加/删除样式表;
激活伪类,如:hover;
操作class属性;
这些都是显而易见的,或许你已经有过这样的体会,不间断地改变浏览器窗口大小,导致UI反应迟钝(某些低版本IE下甚至直接挂掉),现在你可能恍然大悟,没错,正是一次次的重排重绘导致的!
常见引起重排属性和方法 | |||
---|---|---|---|
width | height | padding | margin |
display | border-width | border | top |
position | font-size | float | text-align |
overflow | font-weight | top | left |
font-family | line-height | vertical-align | right |
clear | white-space | bottom | min-height |
offsetTop |
offsetLeft |
offsetWidth |
offsetHeight |
scrollTop |
scrollLeft |
scrollWidth |
scrollHeight |
clientTop |
clientLeft |
clientWidth |
clientHeight |
getComputedStyle() |
(currentStyle in IE) |
||
getBoundingClientRect() |
|||
scrollIntoViewIfNeeded() |
重排影响的范围:
触发重排时会对周围DOM重新排列,影响的范围有两种:
- 全局范围:从根节点
html
开始对整个渲染树进行重新布局。 - 局部范围:对渲染树的某部分或某一个渲染对象进行重新布局
2.引起重绘的情况
常见的重绘元素 | |||
---|---|---|---|
color | border-style | visibility | background |
text-decoration | background-image | background-position | background-repeat |
outline-color | outline | outline-style | border-radius |
outline-width | box-shadow | background-size |
3.如何减少重排(Reflow)和重绘(Repaint)
重排和重绘是DOM编程中耗能的主要原因之一。
CSS中避免重排、重绘
- 避免设置多层内联样式;
- 尽可能在DOM树的最末端改变class;
- 动画效果应用到position属性为absolute或fixed的元素上;
- 避免使用table布局,table属性变化使用会直接导致布局重排或者重绘;(table及其内部元素除外,它可能需要多次计算才能确定好其在渲染树中节点的属性,通常要花3倍于同等元素的时间。这也是为什么我们要避免使用table做布局的一个原因。)
- 不要在布局信息改变的时候做查询(会导致渲染队列强制刷新);
- 用translate替代top改变;
- 用opacity替代visibility(在独立图层下优化重绘)多用visibility:hidden少用display:none;
- 使用css3硬件加速,可以让
transform、opacity、filters
等动画效果不会引起回流重绘。
JS操作避免重排、重绘
- 减少直接操作dom元素,不要一条一条地修改 DOM 的样式,改用className用于控制;
- 不要把 DOM 结点的offsetLeft等属性值放在一个循环里当成循环里的变量;
- 如果需要创建多个DOM节点,可以使用DocumentFragment创建一个子树,之后一次性的拷贝到document;
- 先隐藏元素,进行修改后再显示该元素,因为display:none上的DOM操作不会引发回流和重绘;
- 对于复杂动画效果,使用绝对定位让其脱离文档流,否则会引起父元素及后续元素大量的回流。
4.硬件加速
硬件加速因此也叫 GPU 加速,是利用 GPU 进行渲染,减少 CPU 操作的一种优化方案。由于 GPU 中的 transform 等 CSS 属性不会触发重绘,所以能大大提高网页的性能。
可以通过添加以下 CSS 的 will-change
属性来设置硬件加速:
will-change
为web开发者提供了一种告知浏览器该元素会有哪些变化的方法,这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作。
.btn-5 {
will-change: transform;
}
will-change
允许向浏览器声明将要为所选元素设置动画,并且应该针对这种情况进行优化,这样浏览器会一直让 GPU 处理这个元素。不再需要 CPU 和 GPU 之间的切换,不再有 卡入到位 的现象。
CSS 中的以下属性能触发硬件加速:
- transform
- opacity
- filter
- will-change