# 05 | 渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的? 在[上一篇文章](https://time.geekbang.org/column/article/117637)中我们介绍了导航相关的流程,那导航被提交后又会怎么样呢?就进入了渲染阶段。这个阶段很重要,了解其相关流程能让你“看透”页面是如何工作的,有了这些知识,你可以解决一系列相关的问题,比如能熟练使用开发者工具,因为能够理解开发者工具里面大部分项目的含义,能优化页面卡顿问题,使用JavaScript优化动画流程,通过优化样式表来防止强制同步布局,等等。 既然它的功能这么强大,那么今天,我们就来好好聊聊**渲染流程**。 通常,我们编写好HTML、CSS、JavaScript等文件,经过浏览器就会显示出漂亮的页面(如下图所示),但是你知道它们是如何转化成页面的吗?这背后的原理,估计很多人都答不上来。 ![](https://static001.geekbang.org/resource/image/2b/79/2b08a85c63bee68c6fd95dabb648fd79.png) 渲染流程示意图 从图中可以看出,左边输入的是HTML、CSS、JavaScript数据,这些数据经过中间渲染模块的处理,最终输出为屏幕上的像素。 这中间的**渲染模块**就是我们今天要讨论的主题。为了能更好地理解下文,你可以先结合下图快速抓住HTML、CSS和JavaScript的含义: ![](https://static001.geekbang.org/resource/image/31/e6/31cd7172f743193d682d088a60cb44e6.png) HTML、CSS和JavaScript关系图 从上图可以看出,**HTML的内容是由标记和文本组成**。标记也称为**标签**,每个标签都有它自己的语义,浏览器会根据标签的语义来正确展示HTML内容。比如上面的`

`标签是告诉浏览器在这里的内容需要创建一个新段落,中间的文本就是段落中需要显示的内容。 如果需要改变HTML的字体颜色、大小等信息,就需要用到CSS。CSS又称为**层叠样式表,是由选择器和属性组成**,比如图中的p选择器,它会把HTML里面`

`标签的内容选择出来,然后再把选择器的属性值应用到`

`标签内容上。选择器里面有个color属性,它的值是red,这是告诉渲染引擎把`

`标签的内容显示为红色。 至于**JavaScript(简称为JS),使用它可以使网页的内容“动”起来**,比如上图中,可以通过JavaScript来修改CSS样式值,从而达到修改文本颜色的目的。 搞清楚HTML、CSS和JavaScript的含义后,那么接下来我们就正式开始分析渲染模块了。 由于渲染机制过于复杂,所以渲染模块在执行过程中会被划分为很多子阶段,输入的HTML经过这些子阶段,最后输出像素。我们把这样的一个处理流程叫做**渲染流水线**,其大致流程如下图所示: ![](https://static001.geekbang.org/resource/image/92/e8/9259f8732ddad472e5e08a633ad46de8.png) 渲染流水线示意图 按照渲染的时间顺序,流水线可分为如下几个子阶段:构建DOM树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。内容比较多,我会用两篇文章来为你详细讲解这各个子阶段。接下来,在介绍每个阶段的过程中,你应该重点关注以下三点内容: * 开始每个子阶段都有其**输入的内容**; * 然后每个子阶段有其**处理过程**; * 最终每个子阶段会生成**输出内容**。 理解了这三部分内容,能让你更加清晰地理解每个子阶段。 ## 构建DOM树 为什么要构建DOM树呢?**这是因为浏览器无法直接理解和使用HTML,所以需要将HTML转换为浏览器能够理解的结构——DOM树**。 这里我们还需要简单介绍下什么是**树结构**,为了更直观地理解,你可以参考下面我画的几个树结构: ![](https://static001.geekbang.org/resource/image/fc/38/fcad0a4e3e73c796f00d6120284a3638.png) 树结构示意图 从图中可以看出,树这种结构非常像我们现实生活中的“树”,其中每个点我们称为**节点**,相连的节点称为**父子节点**。树结构在浏览器中的应用还是比较多的,比如下面我们要介绍的渲染流程,就在频繁地使用树结构。 接下来咱们还是言归正传,来看看DOM树的构建过程,你可以参考下图: ![](https://static001.geekbang.org/resource/image/12/79/125849ec56a3ea98d4b476c66c754f79.png) DOM树构建过程示意图 从图中可以看出,构建DOM树的**输入内容**是一个非常简单的HTML文件,然后经由HTML解析器解析,最终输出树状结构的DOM。 为了更加直观地理解DOM树,你可以打开Chrome的“开发者工具”,选择“Console”标签来打开控制台,然后在控制台里面输入“document”后回车,这样你就能看到一个完整的DOM树结构,如下图所示: ![](https://static001.geekbang.org/resource/image/47/73/47f57c3eee749dd838939bfe5dd64573.png) DOM可视化 图中的document就是DOM结构,你可以看到,DOM和HTML内容几乎是一样的,但是和HTML不同的是,DOM是保存在内存中树状结构,可以通过JavaScript来查询或修改其内容。 那下面就来看看如何通过JavaScript来修改DOM的内容,在控制台中输入: ``` document.getElementsByTagName("p")[0].innerText = "black" ``` 这行代码的作用是把第一个`

`标签的内容修改为black,具体执行结果你可以参考下图: ![](https://static001.geekbang.org/resource/image/e7/74/e730aa1d73c1151c588e2f8c7e22c274.png) 通过JavaScript修改DOM 从图中可以看出,在执行了一段修改第一个`

`标签的JavaScript代码后,DOM的第一个p节点的内容成功被修改,同时页面中的内容也被修改了。 好了,现在我们已经生成DOM树了,但是DOM节点的样式我们依然不知道,要让DOM节点拥有正确的样式,这就需要样式计算了。 ## 样式计算(Recalculate Style) 样式计算的目的是为了计算出DOM节点中每个元素的具体样式,这个阶段大体可分为三步来完成。 ### 1\. 把CSS转换为浏览器能够理解的结构 那CSS样式的来源主要有哪些呢?你可以先参考下图: ![](https://static001.geekbang.org/resource/image/bc/7c/bc93df7b8d03b2675f21e1d9e4e1407c.png) HTML加载CSS的三种方式 从图中可以看出,CSS样式来源主要有三种: * 通过link引用的外部CSS文件 * `