CSS解析器和规则匹配处于DOM树建立之后,RenderObject树建立之前,CSS解释器解释后的结果会保存起来。然后RenderObject树基于此结果来进行规范匹配和布局计算。

布局计算

当Webkit创建RenderObject对象之后,每个对象是不知道自己的位置,大小等信息的,WebKit根据盒子模型来计算他的位置,大小等信息,这个过程就是布局计算。

布局计算是一个复杂的过程,我简单的可以总结为:界面是由很多很多的框模型组成的,每个框模型是由元素的类型以及display属性决定的。而不同的Box会参与到不同的格式上下文中(Formatting Context),完成布局的计算。

格式上下文

格式上下文指的是页面中的一块渲染区域,并且这个格式上下文有一套自己的渲染规则。格式上下文决定了其内部元素将如何定位,以及和其他元素之间的关系。
格式上下文分为两种:

  1. 块级格式上下文(Block Formatting Context, BFC)。
  2. 行级格式上下文(Inline Formatting Context, IFC)。

BFC

BFC,它是一个独立的渲染区域,只有块盒子参与。块级格式上下文规定了内部的块盒子是如何布局的,且这个渲染区域与外部毫不相关。下面这些内容非常重要

BFC

W3C标准描述BFC的特点共有两条:

  1. 在一个BFC中,盒子从顶端开始垂直一个接一个的排列,两个相邻盒子之间的垂直间距有margin属性决定。同一个BFC中,两个相邻盒子之间的垂直方向上的外边距会叠加。
  2. 在一个BFC中,每一个盒子的左外边界(margin-left)会紧贴着容器的左边(border-left)(对于从右到左的格式化,则相反),即使存在浮动元素也是如此。 通过上面W3C的定义,我们可以得到以下几个重要的结论:
  3. 在一个BFC内部,盒子会在垂直方向上一个接一个的排列。
  4. 在一个BFC内部,相邻的margin-top和margin-bottom会叠加。
  5. 在一个BFC内部,每一个元素的左外边界(margin-left)会紧贴着包含何止的左边(border-left),即使存在浮动也是如此。
  6. 在一个BFC内部,如果存在内部元素是一个新的BFC,并且存在内部元素是浮动元素。则该BFC的区域不会与float元素的区域重叠。
  7. BFC就是页面上的一个隔离盒子,该盒子内部的子元素不会影响到外面的元素。
  8. 计算一个BFC的高度时,其内部浮动元素的高度也会参与计算。

好说了这么多,那么我们可以通过BFC来干什么呢?

  1. 根据第1条,我们可以通过BFC来避免垂直外边距的叠加。
  2. 通过第6条,我们可以用来清除浮动,其实浮动就是有内容塌陷造成的。
  3. 通过第4条,我们可以用来实现一个自适应的布局。
如何创建BFC

W3C标准中对BFC的定义: 浮动元素,绝对定位元素(position为absolute或fixed),元素display属性为inline-block,table-caption,table-cell,以及overflow属性不为visible的元素将会创建一个新的块级格式上下文(BFC);
如果一个元素具备以下任何一条,则该元素都会创建一个新的BFC。

  1. 根元素。
  2. float属性除none以外的值,也就是“float:left”和“float:right”。
  3. position属性除了static和relative以外的值,也就是“position:absolute”和“position:fixed”。
  4. overflow属性除了visible以外的值,也就是”overflow:auto”,”overflow:hidden”和“overflow:scroll”.
  5. display属性为inline-block,table-caption,table-cell。

如果我们需要创建一个BFC来解决问题。那么我们只需要在CSS中添加上面任意一个属性即可,当然,他们也会带来副作用。

IFC

在行内格式化上下文中,盒是从包含块的顶部开始一个挨一个水平放置的。这些盒之间的水平外边距,边框和内边距都有效。盒可能会以不同的方式垂直对齐:以它们的底部或者顶部对齐,或者以它们里面的文本的基线对齐。包含来自同一行的盒的矩形区域叫做行框

行框的宽度由包含块和浮动情况决定,行框的高度由行高的计算小节给出的规则决定

行框总是足够高,能够容纳它包含的所有盒。然而,它可能比它所包含的最高的盒还要高(例如,如果盒是以基线对齐的)。当盒B的高度小于它所在的行框的高度时,行框中B的垂直对齐方式由’vertical-align’属性决定。当几个行内级盒在水平方向上不能共存于一个行框时,它们会被分到两个或多个垂直堆叠的(vertically-stacked) 行框里。因此,段落就是个行框的垂直栈(vertical stack)。行框没有垂直间隔地堆放(除非在其它地方有特别说明)并且它们不会重叠

一般来说,一个行框的左边界挨着其包含块的左边界,右边界挨着其包含块的右边界。然而,浮动盒可能会跑到包含块边界与行框边界之间。因此,尽管同一个行内格式化上下文中的行框一般都有相同的宽度(即包含块的宽度),如果可用的水平空间因为浮动而减少了的话,它们的宽度就可能不同。同一个行内格式化上下文中的行框一般高度各不相同(例如,一行可能含有一个高图片,而其它的只含文本)

当一行的行内级盒的总宽度小于它们所在的行框的宽度时,它们在行框里的水平分布由’text-align’属性决定。如果该属性值为’justify’,用户代理可能还会拉伸行内盒(不包括inline-table和inline-block盒)里的空格和单词

当行内盒超出行框宽度时,它会被分成几个盒,并且这些盒会跨多行框分布。如果一个行内块无法分割(例如,如果该行内盒(只)含单一字符,或者特定语言的单词分隔规则不允许在该行内盒里分隔,或该行内盒受到了一个值为nowrap或者pre的white-space的影响),那么该行内盒会从行框溢出

当一个行内盒被分割后,外边距,边框和内边距在发生分割的地方(或者在任何分割处,如果有多处的话)没有视觉效果

同一个行框里的行内盒也可能因为双向(bidirectional)文本处理而被分割成几个盒

需要盛放(hold)行内格式化上下文中的行内级内容时,创建一个行框。该行框不含文本、保留空白符(preserved white space)、外边距,内边距和边框非0的行内元素、 以及其它流内内容(例如,图片,行内块或行内表格),并且不以保留换行符结束的(行框)在确定其内部元素的位置时必须被当做0高度行框,出于其他目的时,必须当它不存在