导航被提交后就进⼊了渲染阶段。
构建DOM树
为什么要构建DOM树呢?
这是因为浏览器⽆法直接理解和使⽤HTML,所以需要将HTML转换为 浏览器能够理解的结构——DOM树。

样式计算
样式计算的⽬的是为了计算出DOM节点中每个元素的具体样式
把CSS转换为浏览器能够理解的结构

CSS样式来源主要有上面三种
浏览器也是⽆法直接理解这些纯⽂本的CSS样式,所以当渲染引擎接收到 CSS⽂本时,会执⾏⼀个转换操作,将CSS⽂本转换为浏览器可以理解的结构—— styleSheets。
只需要在控制台中输⼊ document.styleSheets,然后就看到如下图所⽰的结构:
)
转换样式表中的属性值,使其标准化
接下来就要对其进⾏属性值的标准化操作
的CSS⽂本中有很多属性值,如2em、blue、bold,这些类型数值不容易被渲染引 擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值

计算出DOM树中每个节点的具体样式
样式计算过程中的第一个规则是CSS继承。
CSS继承就是每个DOM节点都包含有⽗节点的样式
样式计算过程中的第⼆个规则是样式层叠。
层叠是CSS的⼀个基本特征,它是⼀个定义了如何合 并来⾃多个源的属性值的算法。它在CSS处于核⼼地位,CSS的全称“层叠样式表”正是强调了这 ⼀点。
这个阶段最终输出的内容是每个DOM节点的样式,并被保存 在ComputedStyle的结构内。
布局阶段
接下来就需要计算出DOM树中可⻅元素的⼏何位置,我们把这个计 算过程叫做布局。
创建布局树
在显⽰之前,我们还要额外地构建⼀棵只包含可⻅元素布局树

从上图可以看出,DOM树中所有不可⻅的节点都没有包含到布局树中
为了构建布局树,浏览器⼤体上完成了下⾯这些⼯作:
为了构建布局树,浏览器⼤体上完成了下⾯这些⼯作:
⽽不可⻅的节点会被布局树忽略掉,如head标签下⾯的全部内容,再⽐如body.p.span这个元 素,因为它的属性包含 dispaly:none,所以这个元素也没有被包进布局树。
布局计算
接下来,就计算布局树节点的坐标位置
分层
现在我们有了布局树,因为⻚⾯中有很多复杂的效果,如⼀些复杂的3D变换、⻚⾯滚动,或者使⽤z-indexing做z轴排序等,为了 更加⽅便地实现这些效果,渲染引擎还需要为特定的节点⽣成专⽤的图层,并⽣成⼀棵对应的图层树
浏览器的⻚⾯实际上被分成了很多图层,这些图层叠加后合成了最终的⻚⾯

浏览器的⻚⾯实际上被分成了很多图层,这些图层叠加后合成了最终的⻚⾯。
但并不是布局树的每个节点都包含⼀个图层,如果⼀个节点没有对应的层,那么这个节点就从属 于⽗节点的图层。
那么需要满⾜什么条件,渲染引擎才会为特定的节点创建新的层呢?
第⼀点,拥有层叠上下⽂属性的元素会被提升为单独的⼀层。

第⼆点,需要剪裁(clip)的地⽅也会被创建为图层。
<style>
div {
width: 200;
height: 200;
overflow:auto;
background: gray;
}
</style>
<body>
<div >
<p>所以元素有了层叠上下⽂的属性或者需要被剪裁,那么就会被提升成为单独⼀层,你可以参看下图:</p>
<p>从上图我们可以看到,document层上有A和B层,⽽B层之上⼜有两个图层。这些图层组织在⼀起也是⼀颗树状结构。</p>
<p>图层树是基于布局树来创建的,为了找出哪些元素需要在哪些层中,渲染引擎会遍历布局树来创建层树(Update LayerTree)。</p>
</div>
</body>
在这⾥我们把div的⼤⼩限定为200 * 200像素,⽽div⾥⾯的⽂字内容⽐较多,⽂字所显⽰的区域肯定会超出 200 * 200的⾯积,这时候就产⽣了剪裁
出现这种裁剪情况的时候,渲染引擎会为⽂字部分单独创建⼀个层,如果出现滚动条,滚动条也会被提升为 单独的层。

图层绘制
在完成图层树的构建之后,渲染引擎会对图层树中的每个图层进⾏绘制
渲染引擎实现图层的绘制与之类似,会把⼀个图层的绘制拆分成很多⼩的绘制指令,然后再把这些指令按照 顺序组成⼀个待绘制列表,如下图所⽰:

栅格化(raster)操作

当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)给合成线程
我们把⽤⼾可以看到的这个部分叫做视⼝ (viewport)。
有的图层可以很⼤,⽐如有的⻚⾯你使⽤滚动条要滚动好久才能滚动到底部,但是通过视 ⼝,⽤⼾只能看到⻚⾯的很⼩⼀部分,所以在这种情况下,要绘制出所有图层内容的话,就会产⽣太⼤的开 销,⽽且也没有必要。
基于这个原因,合成线程会将图层划分为图块(tile)
合成线程会按照视⼝附近的图块来优先⽣成位图,实际⽣成位图的操作是由栅格化来执⾏的。所谓栅格 化,是指将图块转换为位图。
合成和显⽰
⼀旦所有图块都被光栅化,合成线程就会⽣成⼀个绘制图块的命令⸺“DrawQuad”,然后将该命令提交 给浏览器进程。
到这⾥,经过这⼀系列的阶段,编写好的HTML、CSS、JavaScript等⽂件,经过浏览器就会显⽰出漂亮的 ⻚⾯了。
整个渲染流程:

⼀个完整的渲染流程⼤致可总结为如下:
- 渲染进程将HTML内容转换为能够读懂的DOM树结构。
- 渲染引擎将CSS样式表转化为浏览器可以理解的styleSheets,计算出DOM节点的样式。
- 创建布局树,并计算元素的布局信息。
- 对布局树进⾏分层,并⽣成分层树。
- 为每个图层⽣成绘制列表,并将其提交到合成线程。
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
- 合成线程发送绘制图块命令DrawQuad给浏览器进程。
- 浏览器进程根据DrawQuad消息⽣成⻚⾯,并显⽰到显⽰器上。
相关概念
更新了元素的⼏何属性(重排)

如果你通过JavaScript或者CSS修改元素的⼏何位置属性,例如改变元素的宽度、⾼度 等,那么浏览器会触发重新布局,解析之后的⼀系列⼦阶段,这个过程就叫重排。
重排需要更新完整 的渲染流⽔线,所以开销也是最⼤的。
更新元素的绘制属性(重绘)
⽐如通过JavaScript更改某些元素的背景颜⾊

如果修改了元素的背景颜⾊,那么布局阶段将不会被执⾏,因为并没有引起⼏何位置的变 换,所以就直接进⼊了绘制阶段,然后执⾏之后的⼀系列⼦阶段,这个过程就叫重绘
重绘省去了布局和分层阶段,所以执⾏效率会⽐重排操作要⾼⼀些。
直接合成阶段
如果你更改⼀个既不要布局也不要绘制的属性,渲染引擎将跳过布局和绘制,只执⾏ 后续的合成操作,我们把这个过程叫做合成

因为是在⾮主线程上合成,并没有占⽤主线程的资源,另外也避 开了布局和绘制两个⼦阶段,所以相对于重绘和重排,合成能⼤⼤提升绘制效率。