现代浏览器的工作原理(三)

解析CSS的流程

  现代浏览器解析CSS的流程如图1所示。

现代浏览器解析CSS的流程

图 1 现代浏览器解析CSS的流程

  现代浏览器解析CSS的流程与解析html的流程类似:从网络或者本地获取CSS文件后,经过解码器、预处理器、标记生成器以及树构建器处理之后生成一个CSSStyleSheet对象。解析流程中的关键处理步骤说明如下:
  (1)Byte Stream Decoder(字节流解码器):将获取到的CSS字节流解析成Unicode编码表示的字符流。关于更多解码细节,可以查看CSS3标准文档
  (2)Input Stream Preprocessor(输入字符流预处理器):对解码产生的Unicode字符流进行预处理。主要进行如下两个操作:1、将所有的单个”回车(CR)”字符、”翻页(FF)”字符以及”回车换行(CRLF)”字符对替换成单个”换行(LF)”字符。2、将所有的”空(U+0000 NULL)”字符替换成”替换(U+FFFD REPLACEMENT CHARACTER)”字符。
  (3)Tokenizer(标记生成器):处理步骤(2)生成的字符流,生成CSS标记并将标记传送给树生成器。CSS标记有多种,如标识符标记()、@标记()、数字标记()。CSS3标准文档给出了CSS标记的具体定义,可以查看CSS3标准文档来获得每个CSS标记的具体定义。标记生成器的标记化算法可以用状态机来表示,具体的算法实现流程可以参阅CSS3标准文档
  (4)Tree Construction(树构建):根据标记生成器产生的一系列CSS标记,构建CSSOM树,树的根节点是CSSStyleSheet对象。CSSStyleSheet对象包含CSSRule对象,CSSRule对象又包含Selectors对象和Declaration对象以及其他与CSS语法对应的对象。

解析CSS示例

以下CSS片段被解析之后生成的CSSOM树如图2所示。

1
2
3
4
5
6
7
div {
background: blue;
}
div p {
font-size: 16px;
}

CSS解析示例

图 2 CSS解析示例

构建呈现树

  浏览器在解析构架DOM树的同时,还会构建呈现树。呈现树是由可视化元素按照其显示顺序组成的树,是文档的可视化表示。Firefox将呈现器中的元素称为”框架(frame)”,Webkit将其称之为”呈现器(renderer)”或者”呈现对象(render object)”。
  呈现器(呈现对象)知道如何布局以及将自身及其子元素绘制出来。每一个呈现器都代表了一个矩形区域,通常对应于相关节点的CSS框,包含诸如宽度、高度、位置等几何信息。节点CSS样式中display属性的不同,浏览器创建出的呈现器的类型也不同,如’inline’和’block’。浏览器创建呈现器时也会考虑元素类型,有些特殊的元素类型对应特殊的呈现器(框架),如表单。

呈现树和DOM树的关系

  呈现树与DOM树相对应,但并不是一一对应的。非可视化的元素(如head元素、display属性为none的元素)不会被插入到呈现树中。(注:visibility属性值为hidden的元素会被插入到呈现树中)
  对于一些具有复杂结构的元素,其无法用单一的矩形来描述,浏览器会为这些元素创建多个可视化对象。如“select”元素有 3 个呈现器:一个用于显示区域,一个用于下拉列表框,还有一个用于按钮。一个Text节点也可能对应多个可视化对象,如当宽度不够时,文本无法在一行中显示而分为多行,那么新的行也会作为新的呈现器而添加。
  还有一些呈现对象在呈现树中所处的位置与DOM节点在DOM树中所处的位置并不对应。对于设置了浮动和定位的元素就会出现这种情况,这些元素处于文档的正常流程之外,其对应的呈现对象放置在呈现树的其他地方并映射到真正的呈现器(框架),放在原位的是占位框架。
  图3显示了DOM树与呈现树的对应关系(引用地址

CSS解析示例

图 3 DOM树与呈现树的对应关系

  在DOM树构建的过程中,浏览器遇到html或者body标记就会创建呈现树的根节点。这个根节点呈现对象对应于CSS的容器block,该block包含了所有其他的block,是最上层的block。这个block的尺寸就是浏览器的视口大小,Firefox称之为ViewPortFrame,Webkit称之为RenderView。呈现树的其余部分将会以DOM树节点插入的形式来创建。

参考文献

  1. https://www.html5rocks.com/en/tutorials/internals/howbrowserswork/
  2. https://www.w3.org/TR/html5/syntax.html