CSS-回流(reflow)与重绘(repaint)

什么是回流(重排)和重绘?

  • 1、回流:渲染树中的一部分或全部元素的尺寸、布局、隐藏等属性改变时,会引起渲染树重新构建,这就叫回流(reflow),也叫重排。比如调整窗口大小、设置字体大小、dispaly、获取实时属性offset系列、用户在input输入、激活CSS伪类:hover等等。

  • 2、重绘:当一些元素的可见性发生变化时,会引起重绘。比如outline、visibility、backgound-color等的变化。

  • 3、第一次渲染时一定会有回流和重绘。回流一定会引起重绘,重绘不一定引起回流。

  • 三个演示渲染过程的视频:
    http://www.youtube.com/watch?v=nJtBUHyNBxs
    http://www.youtube.com/watch?v=ZTnIxIA5KGw
    http://www.youtube.com/watch?v=dndeRnzkJDU

如何减少回流(reflow)、重绘(repaint)?

  • 一、 CSS中避免回流、重绘或将它们的性能影响降到最低
    1.尽可能在DOM树的最末端改变class。节点越靠前,回流影响的性能消耗越大。
    2.避免设置多层内联样式
    3.复杂动画效果应用到position属性为absolute或fixed的元素上,这些元素不影响其他元素,只是这些元素进行重新绘制。可以避免引起父元素以及后续元素的频繁回流。
    4.避免使用table布局。因为表格中任意一个小变化都会导致表格内的其他节点回流
    5.使用css3硬件加速,不会引起回流重绘
    常见的可以触发硬件加速的属性:
1
2
3
4
transform
opacity
filters
Will-change
  • 二、 JS操作避免回流、重绘
    1、假设要多次操作dom,应该在当前DOM树之外重新设置一个子树,全部操作完毕后再插入或替换DOM树的节点
    e.g.:
1
2
3
4
5
6
cosnt childNode = document.createElement(div);
for(let i = 0; i <= 10; i += 1;) {
cosnt item = document.createElement(p);
childNode.appendChild(item);
}
document.body.appendChild(childNode);

2.避免使用JS一个样式修改完接着改下一个样式,最好一次性更改CSS样式,或者将样式列表定义为class的名称
e.g.:

1
2
3
4
5
6
const ele = document.getElementById('app');
ele.style.backgroundColor = '#ccc';
ele.style.width = '100px';
ele.style.height = '100px';
应该写为:
ele.style.cssText += 'backround-color: #ccc; width: 100px; height: 100px;';

3.先隐藏元素,进行修改后再显示该元素,因为display:none上的DOM操作不会引发回流和重绘
4.避免循环读取offsetLeft等属性,在循环之前把它们存起来。下面这些属性会引起回流

1
2
3
4
5
offsetLeft/Top/Right/Bottom
scrollHeight/scrollWidth/scrollLeft/scrollRight
clientTop/Right/Bottom/Left
getComputedStyle() // 获取当前样式
getBoundingClientRect

使用举例:

1
2
3
4
ele.offsetTop += 1;
写为:
const eleTop = ele.offsetTop;
eleTop += 1;

5.对于复杂动画效果,使用绝对定位让其脱离文档流,否则会引起父元素及后续元素大量的回流
动画性能调试方法(以chrome为例):
stack