可视化格式模型和各种框

可视化格式模型

在可视化格式模型中,文档树中的每个元素会根据框模型(box model)产生零到多个框。

不解:根据框模型产生零到多个框,产生的框指的是什么?是box model中的content box、padding box、border box、margin box吗?如果是,那么在布局中应用的所谓“主要的框(principal box)”指的又是以上哪一个呢?
可能的解答:根据W3help:1. 元素生成的框会扮演它子孙元素包含块的角色;2. 元素定位为staitc或relative的元素,其包含块由离它最近的块级、table-cell和inline-block祖先元素的内容框创建。推断主要的框恐怕是元素的内容框(content box)。

这些框的布局被以下因素管理:

  • 框的尺寸和类型
  • 定位体系(常规流、浮动和绝对定位)
  • 在文档树中元素之间的关系(比如一个块元素包含两个互为兄弟节点的浮动元素,后面那个浮动元素的布局会受前面元素以及它的包含块的影响)
  • 外部因素(如viewport,即可视窗口的大小,图片的固有尺寸会影响行内替换性元素的尺寸,从而影响布局)

简单说,可视化格式模型的定义就是,文档树中的每个元素都会根据框模型产生零个到多个框,这些框的布局被我们所熟知的各种因素统治着。

不同类型的框

  • 包含块(containing block)
  • 块级元素(block-level element)
  • 块元素(block element)
  • 块级框(block-level box)、块容器框(block container box)、块框(block box)
  • 行内级元素(inline-level element)
  • 行内元素(inline element)
  • 行内级框(inline-level box)、原子行内级框(atomic inline-level box)、行内框(inline box)
  • 匿名框(anonymous box)

包含块(containing block)

根元素

根元素的包含块叫做初始包含块(initial containing block)。在HTML中,根元素是html元素。初始包含块的direction属性与根元素相同。

static和relative定位元素

position为static或relative的元素,包含块由最近的祖先块容器框创建。

相关名词定义

  • 块级元素:视觉上会被格式化成块状的元素。display为block、list-item、table、flex、grid的元素。
  • 块容器框:除table boxes和替换性元素以外的块级元素、非替换性性inline-block元素和非替换性性table cell元素。

fixed定位元素

position为fixed的元素,包含块为当前可视窗口。

absolute定位元素

position为absolute的元素,包含块为离它最近的position不为static的祖先元素创建。

如果其祖先元素是行内元素,则包含块取决于其祖先元素的direction特性

  • 如果direction是ltr,包含块的顶、左边是祖先元素生成的第一个框的顶、左内边距边界,右、下边是祖先元素生成的最后一个框的右、下内边距边界。(以内联元素内有文字为例,包含块左右内边界就是文字的起始和终结点竖直方向的线。非常毁三观……)
1
2
3
4
5
6
7
8
9
<p style="border:1px solid red; width:200px; padding:20px;">
T
<span style="background-color:#C0C0C0; position:relative;">
这段文字从左向右排列,红 XX 和 蓝 XX 和黄 XX 都是绝对定位元素,它的包含块是相对定位的SPAN。 可以通过它们绝对定位的位置来判断它们包含块的边缘。
<em style="position:absolute; color:red; top:0; left:0;">XX</em>
<em style="position:absolute; color:yellow; top:20px; left:0;">XX</em>
<em style="position:absolute; color:blue; bottom:0; right:0;">XX</em>
</span>
</p>

行内元素创建的包含块
包含块的宽度可能为负

  • 如果direction是rtl,包含块的顶、右边是祖先元素生成的第一个框的顶、右内边距边界,左、下边是祖先元素生成的最后一个框的左、下内边距边界。
1
2
3
4
5
6
7
8
9
<p style="border:1px solid red; width:200px; padding:20px; direction:rtl;">
T
<span style="background-color:#C0C0C0; position:relative;">
这段文字从右向左排列,红 XX 和 蓝 XX 和黄 XX 都是绝对定位元素,它的包含块是相对定位的SPAN。可以通过它们绝对定位的位置来判断它们……
<em style="position:absolute; color:red; top:0; left:0;">XX</em>
<em style="position:absolute; color:yellow; top:20px; left:0;">XX</em>
<em style="position:absolute; color:blue; bottom:0; right:0;">XX</em>
</span>
</p>

direction为rtl的行内元素创建的包含块

如果祖先元素不是行内元素,包含块的区域即为祖先元素的内边距边界。

注意到的一个问题

今天第一次注意到的问题:一个元素position:absolute,它的祖先元素overflow:hidden,那么此元素的显示与隐藏【只与它的包含块有关系】。如果包含块没有overflow:hidden,即使包含块的子元素、absolute元素的祖先元素overflow:hidden了,absolute元素仍旧会显示,与自己祖先元素的状态无关。可是,如果包含块的祖先元素overflow:hidden了,那么包含块也会被截断,此时absolute元素也会被截断。也就是说,absolute元素的显示与隐藏仅仅与它的包含块有关。
并且,不管包含块是否被overflow:hidden的祖先元素截断,结果都是一样的,即即使包含块本身就比祖先元素小,包含块内超出包含块超出祖先元素的元素还是会被截掉,显然包含块的子元素在包含块的祖先元素眼中属于包含块的一部分。

块级元素(block-level element)

视觉上被格式化为块状的元素,通俗来说就是会换新行的元素(后半句来自杜瑶博客)。以下display值使一个元素成为块级元素:block、list-item、table(以上来自W3C标准)、flex、grid(后两个来自杜瑶博客)。

不解:那么display: table-row等独占一行但没有被标准提及的元素是否是块级元素?

块元素(block element)

display为block的元素,属于块元素。

块级框(block-level box)、块容器框(block container box)、块框(block box)

块级框(block-level box)

块级元素生成块级框,这些框会参与BFC。每个块级元素都会生成一个主要的块级框来包含其子框和生成的内容,任何定位方式都会与这个主要的块级框有关。

某些块级元素还会在主要的框之外产生额外的框,例如list-item元素,它需要生成一个额外的框用于包含list-style-type。这些额外的框会相对于主要的块级框来进行排版。

不解:块级元素生成的框【们】具体都是什么样子的?主要的框是指块级元素的content box吗?或者margin box?

块容器框(block container box)

除了table box和替换性元素以外,一个块级框也是一个块容器框。一个块容器框只能包含块级框或建立一个IFC只包含行内级框,不能同时包含块级框和行内级框。

不是所有的块容器框都是块级框:非替换性inline-block元素和非替换性table cell元素是块容器框而不是块级框。

简单说,块容器框的定义就是:除了table box和替换性元素之外的块级框,非替换性inline-block元素和非替换性table cell元素。

关于刚刚接触块容器框时的一些疑惑和最终解决的自问自答,以及延伸出来的尚未解决的新疑惑😭:
块容器框(block container box)的定义究竟是什么?

不解:目前感觉好像不止块容器框,所有的框都只能包含块级框或只能包含行内级框,如一个行内框,如果含有一个块级框,则会在块级框两边生成两个匿名块框,同样只能包含块级框。

块框(block box)

既是块级框又是块容器框的就是块框。(即除了table box和替换性元素以外的块级框)

行内级元素(inline-level element)

行内级元素是不会为自身内容生成新的块的元素,内容会分布在各行中。以下display值使一个元素成为行内级元素:inline、inline-table、inline-block。

行内元素(inline element)

display值为inline的元素。

行内级框(inline-level box)、行内框(inline box)、原子行内级框(atomic inline-level box)

行内级框

行内级元素生成行内级框,行内级框参与一个IFC。

行内框

既是行内级框,其内容又参与包含它的IFC的是行内框。一个display: inline的非替换性元素生成一个行内框。

原子行内级框

不是行内框的行内级框(比如替换性行内级元素、inline-block元素和inline-table元素)被称为原子行内级框,因为它们是作为一个单独的不透明框参与它们的IFC的。

匿名框

匿名块框

如果一个块容器框里面有块级框,那么我们强迫它里面只有块级框,即在行内级元素外层生成有匿名块框包裹。

如果一个行内框包含了一个在常规流中的块级框,这个行内框(以及它的在同一个line box里的行内祖先)会被打断在这个块级框(以及所有连续或者只是被可折叠的空格或不在常规流内的元素隔开的块级兄弟元素)的周围,将这个行内框切分为两个框(即使是空的),分别在块级框的两侧。在这个打断之前和之后的line box被封闭在匿名块框中,且这个块级框成为一个那些匿名框的兄弟框。当像这样的一个行内框被相对定位(relative position)影响时,任何结果的转变也会影响到在这个行内框里的块级框。

同时,生成匿名框的元素被设置的属性仍旧适用于这个元素的框和内容。因此,若为生成了被打断的行内框的元素设置border,会出现如图所示情况:

1
2
3
4
5
6
7
p {
display: inline;
}

span {
display: block;
}
1
2
3
4
5
<P>
This is anonymous text before the SPAN.
<SPAN>This is the content of SPAN.</SPAN>
This is anonymous text after the SPAN.
</P>

p元素生成的行内框被打断,但属性仍作用在元素的框上

匿名行内框

任何被直接包含在一个块容器元素的文本(不在一个行内元素中)一定被当做一个匿名行内元素。

因此,如果它的兄弟框中有块框,依照上节匿名块框的内容,它会被一个匿名块框包裹;如果它的兄弟框中只有行内框,则它的父元素则会为它生成一个匿名行内框用以包裹。

参考文献