按照渲染的时间顺序,整体过程可分以下几个
构建DOM树,样式计算,布局阶段,分层,绘制,分块,光栅化和合成
构建dom树
HTML文件转dom树
但是在此时,不知道各节点的样式
样式计算
计算dom节点中每个元素的具体样式
步骤
-
把css转换为浏览器能够理解的结构-stylesheets:
document.styleSheets -
转换样式表中的属性值,使其标准化
- 各种单位转变为可识别的标准化值,例:rem→px等
-
计算出dom树中每个节点的具体样式
- css继承规则和层叠规则
这⾥需要特别提下UserAgent样式,它是浏览器提供的⼀组默认样式
如果你不提供任何样式,默认使⽤的就是UserAgent样式。
布局阶段
现在有dom树和dom树中元素的样式,但是不知道元素的几何位置
计算出dom树中可见元素的几何位置,此计算过程为布局
步骤
-
创建布局树
-
在显示之前,额外的构建一棵只包含可见元素的布局树
- 遍历dom树中所有可见节点,并把这些节点加到布局中
- 不可见的被忽略掉,head、diaplay:none等
-
-
布局计算
- 计算布局树节点的坐标位置
分层
因为页面存在很多复杂的效果,3D变换、z轴排序等。渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(layerTree)
浏览器的⻚⾯实际上被分成了很多图层,这些图层叠加后合成了最终的⻚⾯
并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层
满足任意一点的元素就可以被提升为单独的一个图层
-
拥有层叠上下文属性的元素会被提升为单独的一层
- 明确定位属性的元素、定义透明属性的元素、使⽤CSS滤镜的元素等,都拥有层叠上下⽂ 属性。
-
需要剪裁(clip)的地方也会被创建为图层。
- 例:超出显示区域,显示部分,出现滚动条
图层绘制
对图层树中的每个图层进行绘制
定义:绘制是浏览器根据渲染树中每个节点的样式和内容,将其转换为屏幕上的像素的过程。在这个阶段,浏览器会遍历渲染树,对于每个可见的节点,调用图形绘制 API 来绘制其内容,包括文本、颜色、边框、背景、图像等。
在绘制阶段生成的图形数据通常是以矢量图形或位图的形式存在的
- 填充像素:将布局后的节点转换为屏幕像素,执行文本、颜色、边框等绘制操作。
- 分层绘制:浏览器可能将页面分为多个图层,独立绘制以提高效率。
绘制列表只是用来记录绘制顺序和绘制指令的列表,并没有真正的绘制出页面
栅格化(raster)(光栅化)操作
定义:光栅化是将绘制好的矢量图形或位图图像转换为屏幕上的像素点的过程,即将图形数据转换为可以在屏幕上显示的像素数据。
合成线程会将图层划分为图块(tile),然后光栅化会把这些图块转换为位图,视口附近的图块会优先被处理
合成和显示
- 图层合并:将各图层按正确顺序合成,最终显示到屏幕。
一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令⸺“DrawQuad”,然后将该命令提交 给浏览器进程。 浏览器进程里面有一个叫viz的组件,用来接收合成线程发过来的DrawQuad命令,然后根据DrawQuad命 令,将其⻚面内容绘制到内存中,最后再将内存显示在屏幕上。
总结
- 渲染进程将HTML内容转换为能够读懂的DOM树结构。
- 渲染引擎将CSS样式表转化为浏览器可以理解的styleSheets,计算出DOM节点的样式。
- 创建布局树,并计算元素的布局信息。
- 对布局树进行分层,并生成分层树。
- 为每个图层生成绘制列表,并将其提交到合成线程。
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
- 合成线程发送绘制图块命令DrawQuad给浏览器进程。
- 浏览器进程根据DrawQuad消息生成⻚面,并显示到显示器上。
重排、重绘、合成
重排
改变元素的几何位置会触发重排,重排会触发重新布局,也就是会从布局阶段重新执行一遍
重绘
重绘只是**修改元素的颜色等非位置属性,**会重新触发绘制阶段
合成
合成只会由已提升会合成层的transform或opacity触发,只涉及几何变换或透明度变换,会跳过前面的流程,直接进入合成阶段,开销最小。(transform或opacity若未提升为合成层,则依然会触发paint)