在网易一面的时候问到了重绘和回流,面试之前有看过,但是还是记得很模糊,所以特别写一篇来记一下。
Keyword: 重绘、回流
HTML渲染过程
浏览器在获取到了HTML之后,会把HTML解析成一个DOM树,HTML中的每一个标签都是这个树中的节点。这个树后续可以被JavaScript操作,包含了动态添加的节点,以及在页面中并不渲染的节点(display: none)。
在加载CSS的过程中,浏览器会对CSS进行解析,在其内部构成一个CSSOM(样式结构体)。在解析的过程中识别不了的样式会被浏览器自动忽略。
浏览器在渲染页面时,是利用DOM树和CSSOM进行综合计算,得到一个渲染树(render tree),然后再基于渲染树渲染最终的页面。
渲染树和DOM树很类似,但是二者的区别有很明显,渲染树的节点是包括各种样式的,而且不包括被隐藏了的节点。
特别:visibility: hidden设置后,元素仍然还在渲染树上,在布局上仍然会占用一定的空间。
之所以存在重绘和回流的区别,是因为一些操作可能只是非常小的改变渲染树的元素,并不影响布局,所以浏览器可以做更小消耗的操作。
重绘
重绘指渲染树的元素需要更新一些属性,这些属性仅影响元素的外观、风格,不影响到布局,此时页面会只进行重绘。比如设置background-color。
重绘是回流的一部分,发生了回流那么一定会发生重绘,这使得回流的资源消耗比重绘要大。
重绘对应的CSS属性:
- color
- border-style
- border-radius
- visibility
- background
- text-decoration
- outline
- box-shadow
回流
任何在渲染树中的元素,如果其尺寸、布局、隐藏等情况发生了变化,引起页面布局变化,导致渲染树需要重新构建的时候,这个情况下会进行回流。
引起回流的情况有:
- 添加/删除可见的DOM
- 元素的尺寸发生变化(包括边距、填充、边框)
- 内容出现变化(比如输入了某个文本)
- 浏览器窗口大小改变(resize)
- 计算offsetWidth、offsetHeight
- 改变了某个元素的style属性
- 修改页面字体
需要注意的是,即使你改变的是一个父节点里面的子节点,但是受到影响,父节点也会触发一系列的回流。
由于回流消耗大,为了优化页面,我们需要尽可能减少回流。优化的方法有:
- 利用documentFragment存储页面的一部分元素,在页面里对这一块DOM进行操作,最后再应用一系列的更改。它是在内存中的一块脱离文档树的内容,不会引起回流。
- 不要频繁地更改style,可以用添加、删除class的方式规避一定的归流。
- 尽可能避免使用table布局,table布局很容易发生回流
- 不要频繁获取节点的属性值,比如scrollTop、clientWidth等。