在详细讲解回流和重绘之前,我们了解一下回流和重绘是什么,什么情况下会触发回流和重绘?
回流
当render tree中的一部分或全部,因为元素的大小、布局、隐藏或显示等发生改变时,浏览器就会重新渲染部分DOM或全部DOM的过程,叫做回流。
也可以理解为当盒子的大小、布局、隐藏或显示等发生改变时,浏览器就会重新渲染部分DOM或全部DOM的过程,叫做回流。
重绘
当元素样式改变,但不影响元素在文档流中的位置时,比如:background-color,border-color,visibility等,浏览器只会将新样式赋予元素并进行重新绘制操作。
注:
- 回流必将引起重绘,重绘不一定引起回流
触发回流重绘的操作
- 添加或删除可见的DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。
- 页面一开始渲染的时候(这肯定避免不了)
- 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
接下来我们看看回流和重绘的原理:
首先我们先看看浏览器渲染的过程:
- 解析HTML,形成DOM树,当遇到非阻塞资源时,如图片则会继续解析,当遇到css文件时,也会继续解析。当时遇到了js文件(特别是没有defer和async)的阻塞渲染并停止HTML的解析。
- 构建CSSOM树。浏览器将CSS规则转换为可以理解和使用的样式映射。浏览器遍历CSS中的每个规则集,根据CSS选择器创建具有父、子和兄弟关系的节点树。
- 第三步是将DOM和CSSOM组合成一个Render树,计算样式树或渲染树从DOM树的根开始构建,遍历每个可见节点。像和它的子节点以及任何具有display: none样式的结点,例如script { display: none; }(在user agent stylesheets可以看到这个样式)这些标签将不会显示,也就是它们不会出现在Render树上。具有visibility: hidden的节点会出现在Render树上,因为它们会占用空间。由于我们没有给出任何指令来覆盖用户代理默认值,因此上面代码示例中的script节点将不会包含在Render树中。
- 第四步是在渲染树上运行布局以计算每个节点的几何体。(回流\重排)。在此阶段,考虑到视区大小,浏览器将确定屏幕上所有不同框的尺寸。以视区的大小为基础,布局通常从body开始,用每个元素的框模型属性排列所有body的子孙元素的尺寸,为不知道其尺寸的替换元素(例如图像)提供占位符空间。
- 最后一步是将各个节点绘制到屏幕上。
生成渲染树
- 从DOM树的根开始构建,遍历每个可见节点。
- 对于每一个可见节点,找对应的CSSOM规则。
- 根据每一个可见节点和它们对应的CSSOM规则,结合形成Render Tree.
当render tree中的一部分或全部,因为元素的大小、布局、隐藏或显示等发生改变时,浏览器就会重新渲染部分DOM或全部DOM,这个过程就是回流
当元素样式改变,但不影响元素在文档流中的位置时,比如:background-color,border-color,visibility等,浏览器只会将新样式赋予元素并进行重新绘制操作。而不会发生重绘