HTML CSS JavaScript数据经过渲染模块的处理,最终输出为屏幕上的像素。这中间的渲染模块就是我们今天要讨论的主题。
- 构建DOM树
- 样式计算
- 布局阶段
- 分层
- 图层绘制
- 栅格化操作
- 合成与显示
1. 构建DOM树
因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树。
- 输入:HTML文件
- 处理过程:HTML解析器解析
- 输出:树状结构的DOM树
打开 Chrome 的开发者工具,选择
Console
标签打开控制台,在控制台输入document
并回车,这样就可以看到一个完成的DOM树结构
2. 样式计算
- 输入:CSS文本
-
处理过程:渲染引擎根据分三步完成CSS的解析
1.document.styleSheets;
2.属性值标准化;
3.根据继承规则和层叠规则进行计算) - 输出:每个DOM节点的样式并被保存在ComputedStyle结构内
- 把css转换成浏览器能够理解的结构 -- styleSheets
打开 Chrome 的开发者工具,选择
Console
标签打开控制台,在控制台输入document.styleSheets
并回车,这样就可以看到styleSheets的结构
-
转换样式表中的属性值,使其标准化
- 计算出DOM树中每个节点的具体样式
-
继承规则:DOM节点能继承父节点的可继承样式
-
层叠规则:提供了如何合并来自多个源的属性值的算法
3. 布局阶段
计算 DOM 树中可见元素的几何位置,该计算过程叫做布局。布局阶段需要完成两个任务:创建布局树和布局计算。
- 输入:DOM树 + ComputedStyle结构
- 处理过程:布局处理
- 输出:布局树
-
创建布局树
所有不可见元素都不会包含在布局树中。
布局计算
计算布局树节点的坐标位置并更新布局树 - 该过程比较复杂此处不做展开。
4. 分层
渲染引擎会为特定的节点生成专用的图层并生成一颗对应的图层树。
- 输入:布局树
- 处理过程:渲染引擎处理
- 输出:图层树
打开 Chrome 的开发者工具,选择
Layers
标签就可以看到可视化页面的分层情况
并不是布局树的每个节点都对应一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的层。
需要满足什么条件,渲染引擎才会为特定的节点创建新的图层呢?
满足以下条件之一:
- 拥有层叠上下文属性的元素会被提升为单独的一层
- 需要剪裁的地方也会被创建为图层
5. 图层绘制
在完成图层树的构建之后,渲染引擎会对图层树中的每个图层进行绘制。
渲染引擎会把图层的绘制拆分成很多小的绘制指令,然后再把这些指令按顺序组成一个绘制列表。
栅格化操作
实际上绘制操作是有渲染引擎中的合成线程来完成的。
主线程会把绘制列表提交给合成线程。
合成线程会将图层划分为图块(tile),大小通常为256x256或512x512.
合成线程按照视口附近的图块来优先生成位图。
所谓栅格化就是指将图块转换为位图
6. 合成与显示
一旦所有图块都被栅格化,合成线程就会生成一个绘制图块的命令“DrawQuad”,然后将该命令提交给浏览器进程。
浏览器进程接收合成线程发过来的“DrawQuad”命令然后根据该命令将页面内容绘制到内存中,最后将内存显示在屏幕上。
总结
结合上图,一个完整的渲染流程大致可总结为如下:
- 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
- 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
- 创建布局树,并计算元素的布局信息。
- 对布局树进行分层,并生成分层树。
- 为每个图层生成绘制列表,并将其提交到合成线程。
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
- 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
- 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。
文章内容参考极客时间 李兵老师的浏览器工作原理与实践课程。