stay hungry stay foolish

webkit学习笔记-(6)CSS解释器和样式布局

CSS 基本功能

框模型

框模型是布局计算的基础,渲染引擎可以根据框模型来理解该如何排版元素以及元素之间的位置关系。

包含块模型

当WebKit计算元素的箱子的位置和大小时,WebKit需要计算该元素和另外一个矩形区域的相对位置,这个矩形区域成为该元素的包含块。框模型就是用在包含块内计算和确定各个元素的。

包含块的具体定义如下:

  • 根元素的包含块称为初始包含块,通常它的大小就是可视区域(Viewport)的大小。
  • 对于其他位置属性设置为static或者relative的元素,它的包含块就是最近祖先的箱子模型中内容区域(Content)。
  • 如果元素的位置属性为fixed,难么该元素的包含块脱离HTML文档,固定在可视区域的某个特定位置。
  • 如果元素的位置属性为absolute,那么该元素的包含块由最近的含有属性absolute,relative,fixed的祖先决定。

CSSOM(CSS Object Model)

CSSOM 定义了样式表的接口,称为“CSSStyleSheet”,JavaScript 可以通过该接口动态操作 CSS 样式。例如可以通过 document.stylesheets 查看当前网页中包含的所有 CSS 样式表。

此外,W3C 还定义了另外一个规范,那就是 CSSOM View,它的基本含义是增加一些新的属性到 Window、Document、Element、HTMLElement 和 MouseEvent 等接口,这些 CSS 的属性能够让 JavaScript 获取视图信息,用于表示跟视图相关的特征,例如窗口大小、网页滚蛋位置、元素的框位置、鼠标事件的坐标等信息。

CSS 解释器和规则匹配

CSS 的内部结构主要类和关系:

DocumentStyleSheetCollection 类包含了所有 CSS 样式表,CSSStyleSheet 包含了 CSS 的 href、类型、内容等信息。CSS 的内容就是样式信息 StyleSheetContents,包含了一个样式规则(StyleRuleBase)列表。

StyleSheetResolver 类将解释之后的规则组织起来,用于为 DOM 中的元素匹配相应的而规则,从而应用规则中的属性值序列。它包含了一个 DocumentRuleSets 类,该类用来表示多个规则集合(RuleSet)。每个规则集合都是将之前解释之后的的结果合并起来,并进行分类,例如 id 类规则、标签类规则等。由于规则可能是用户自定义的,也有可能是浏览器默认的,所以会有多个规则集合。

StyleRuleBase 有一个子类 StyleRule,其内部结构如下:

CSS 解释器的工作如下:

样式规则建立完成之后,Webkit 保存规则结果在 DocumentRuleSets 对象类中。当 DOM 的节点建立之后,Webkit 使用 StyleResolver 类根据元素的信息(标签名、类别等),从样式表中查找匹配的规则,然后将样式信息保存到新建的 RenderStyle 对象中。最后,这些 RnederStyle 对象被 RenderObject 类所管理和使用。

当使用 JavaScript 动态设置样式属性值时,JavaScript 引擎会调用设置属性值的公共处理函数,然后该函数调用属性值解析函数。而后 Webkit 将解析后的信息设置到元素的“style”属性中,然后设置标记表明该元素需要重新计算样式,并触发重新计算布局。

Webkit 布局

当 Webkit 创建 RenderObject 对象之后,每个对象是不知道自己的位置、大小等信息的,Webkit 根据框模型来计算它们的位置、大小等信息的过程称为布局计算(或者称为排版)。

布局计算根据其计算的范围大致可以分为两类:第一个类是对整个 RnederObject 树进行的计算;第二类是对 RenderObject 树中的某个子树的计算,常见于文本元素或者是 overflow:auto 快的计算,这种情况一般是其子树布局的改变不会影响到其周围元素的布局。

布局计算是一个递归的过程,一个节点的大小通常需要先计算它的子节点的位置、大小信息。

布局计算主要的主要逻辑都是由 RenderObject 类的“layout”函数来完成。该函数首先需要判断 RenderObject 是否需要重新计算,通常这需要检查位数组中的相应标记位、子女是否需要计算布局等来确定。然后,该函数会确定网页的宽度和垂直方向上的外边距,最后,该函数会遍历其每一个子女节点,依次计算它们的布局,每个子女节点都有自己的“layout”函数。

除非定义了页面元素的宽高,一般来说页面的元素的宽高都是在布局的时候通过相关计算得出来的。如果元素有它的子女,则 Webkit 递归这一过程。

以下情况都有可能使 Webkti 重新计算布局:

  • 首次打开网页
  • 网页中的动画
  • 通过 JavaScript 改变元素的样式
  • 用户的交互,例如翻滚网页