5.1.1 行格式化上下文
默认情况下,所有框都在普通流中定位,普通流包括块级框的块格式化、行内级框的行格式化、块级框和行内级框的相对定位。
在普通流中,不同类型的框,会参与不同的格式化上下文(Formatting Context),格式化上下文就是框的布局上下文,它规定了该上下文中的框如何排列,以及这些框之间的关系和相互作用。
普通流中的每个框,只能参与某一种格式化上下文,要么是块格式化上下文,要么是行格式化上下文。块级框参与块格式化上下文,行内级框参与行格式化上下文。
行格式化上下文
只有行内级框参与的格式化上下文,称作行格式化上下文(Inline Formatting Contexts,简称IFC),它规定了内部的行内级框如何排列。
在行格式化上下文中,行内级框从包含块的顶部开始,一个接一个地水平排列。在布局时,水平方向的外边距、边框和内边距都有效,并通过水平方向的外边距来调整框之间的水平距离。两个相邻的行内级框之间的水平距离,等于第一个框的 margin-right 与第二个框的 margin-left 之和。如图 5‑1 所示:
把包含了一行内所有行内级框的矩形区域,称作行框(line box)。行框是本行一个虚拟的框,是浏览器渲染模型中的一个概念,并没有实际显示出来。
通常情况下,行框的宽度等于其包含块内容区的宽度。行框的左外边界,会紧贴其包含块的左内边界,行框的右外边界,会紧贴包含块的右内边界。
假设在一个段落中,包含三个 span 元素:
<p>
<span>inline element 1</span>
<span>inline element 2</span>
<span>inline element 3</span>
</p>
上述代码中,包含块就是 p 元素的内容边界,行框的边界就是p 元素的内容边界。为了查看效果,为 p 元素定义了内边距和边框,为 span 元素也定义了边框:
p {
padding: 10px;
background: #eee;
border: 1px solid #ccc;
}
span {
background: #fff;
border: 1px dashed #ccc;
}
上述代码的运行效果如图 5‑2 所示:
然而,如果在一行内存在浮动框,浮动框会脱离文档流,并被置于包含块和行框的外边界之间。假设现在让第二个 span 元素向左浮动:
span:nth-child(2) {
float: left;
}
在一行内存在浮动框后的运行效果如图 5‑3 所示:
从上图可以看出,尽管浮动框是第二个子元素,它仍然会紧贴包含块的左内边界。并且,浮动框脱离文档流后,会使行框的宽度变窄。由此可知,尽管同一行内格式化上下文中的行框是等宽的(等于包含块的宽度),浮动框却会使行框的宽度变窄。
如果一行内的多个行内级框的总宽度超过行框的宽度时,行内框将被分割成多个框,这些框又分布在多个垂直堆叠的行框中。但是,如果行内框的 white-space 属性值为 nowrap 或 pre,则该行内框将溢出到行框的外面。而原子行内级框不允许被分割,它将作为一个整体,被置于具有足够空间的行框中。
如果一个行内框被分割,外边距、边框和内边距,不会在所有分割的地方都产生视觉效果,而是仅出现在行内框的开始处和结尾处。假如有一个段落,其中包含重点强调的文本:
<p>为该段落中的<strong>重点强调的文本</strong>设置外边距、边框和内边距</p>
现在,在 strong 元素的左右两侧各添加 1em 的内边距和 1em 的外边距。为了便于观察,为容器 p 添加了 1px的实线边框,为 strong 元素添加了 1px 的虚线边框:
p {
width: 240px;
padding: 10px;
border: 1px solid #ccc;
}
strong {
margin: 0 1em;
padding: 0 1em;
background: #eee;
border: 1px dashed #444;
}
上述代码的运行结果如图 5‑4 所示:
从上图可以看出,行内框的外边距、边框和内边距,仅仅出现在行框的开始处和结尾处,没有出现在每个分割的地方。
一个行框的高度,总是足以容纳一行内的所有行内级框。也就是说,一个行框的高度,就等于本行内所有行内级框中,高度最大者。
一个行内框的高度,总是等于其 line-height 属性的值,垂直方向的外边距、边框、内边距,都不会增加行内框的高度。
假设在 strong 元素的四个方向,均添加 1em 的内边距和外边距:
strong {
margin: 1em;
padding: 1em;
line-height: 1;
background: #eee;
border: 1px dashed #444;
}
运行结果如图 5‑5 所示:
从上图可以看出,垂直方向的外边距、边框、内边距,并没有增加行内框的高度,因为行内框的高度仅仅由它的 line-height 属性决定。
原子行内级框的情况有所不同,它的高度等于margin-box 的高度,也就是说,垂直方向的外边距、边框、内边距,都可以增加原子行内级框的高度。假设为段落中一幅图像应用垂直方向的外边距、边框、内边距:
img {
margin: 10px;
padding: 10px;
background: #ccc;
vertical-align: middle;
border: 1px dashed #444;
}
运行结果如图 5‑6 所示:
从上图可以看出,第一行明显比第二行要高,这是因为垂直方向的外边距、边框、内边距,增加了原子行内级框的高度,进而使行框的高度也相应增加。
由于不同的行框所包含的内容可能不同,比如一行仅包含文本,但另一行可能包含图像、表格等。因此,在同一行内格式化上下文中,行框的高度也不尽相同。如图 5‑7 所示:
在一个行框中,当行内级框 B 的高度小于包含它的行框的高度时,则 B 在行框中垂直对齐的位置,由 B 的 vertical-align 属性决定。
当一行中的行内级框的总宽度,小于包含它们的包含块的宽度时,这些行内级框在行中的水平分布,取决于包含块的 text-align 属性。