当浏览器收到HTML文件后,会产生一个渲染任务,并加入到渲染主线程的任务队列中。
在事件循环下,渲染主线程会取出消息队列的任务开始渲染。
整个渲染流程有多个阶段,分别是:HTML解析、样式计算、布局、分层、绘制、(分块、光栅化)、画
每个阶段都会明确输入输出,上个阶段的输出会成为下个阶段的输入。
HTML解析
解析过程中遇到css解析css,遇到js执行js。为了提高效率浏览器会在解析前开启一个预解析的线程,会先下载HTML中外部的css文件和js文件。
主线程在解析到link元素位置,外部的css文件还没有下载解析好,主线程不会等待,会继续解析后面的HTML代码。如果解析到script元素位置,会停止解析HTML。转而会等待js文件下载完并且执行完js代码。才会继续解析后续的HTML代码。解析完成后会得到DOM树和CSSOM树,浏览器的默认样式、内部外部样式都会包含在CSSOM树上。
样式计算
主线程会遍历得到的DOM树,依次会树中的每个节点计算出它最终的样式。
在这一过程中css的相对单位会变成绝对单位,比如rem转化为px。完成后会得到一颗带有样式的DOM树。
布局
布局完成后会得到布局树。布局的时候会遍历DOM树的每个节点,计算每个节点样式。例如节点的宽高、相对包含块的位置。
大部分的时候DOM树并非和布局树一一对应。比如display: none。
分层
主线程会对布局树进行分层。
分层的好处在于,后面某一层改变,只会对该层进行后续处理,从而提高效率。滚动条、transform、opacity等样式都会影响分层结果。
绘制
主线程会为每层单独绘制指令集,用来描绘这一层内容如何画出来。
绘制完成后主线程会将每层的绘制信息交给合成线层,剩余工作交给合成层工作。
合成层首先会为每个图层进行分块,将其划分为更小的区域。
分块完成后,合成线层会将块信息交给CPU进程,进行光栅化。
光栅化的结果,就是一块一块的位图(每个像素点的信息)。
合成线层拿到每个层,每个块的位图后,会根据指令信息画出其在浏览器的哪个位置。
重排(回流)会重新进行样式计算。重绘会重新进行绘制。