正常流中的块级和行内布局
在本指南中,我们将探讨块级元素和行级元素在作为常规流的一部分时的基本行为。
常规流在 CSS 2.1 规范中定义,该规范解释说,常规流中的任何框都将是格式化上下文的一部分。它们可以是块级的或行级的,但不能同时是两者。我们称块级框参与块格式化上下文,行级框参与行格式化上下文。
具有块级或行级格式化上下文的元素的行为也在此规范中定义。对于具有块级格式化上下文的元素,规范中说:
“在块格式化上下文中,盒子在包含块中自上而下地垂直的一个接一个地排列。两个兄弟盒子之间的垂直距离由 'margin' 属性决定。在块格式化上下文中,相邻的块级盒子之间的垂直外边距会合并。”
“在块格式化上下文中,每个盒子的左外边缘都接触包含块的左边缘(对于从右到左的格式,则右边缘接触)。” - 9.4.1
对于具有行级格式化上下文的元素:
“在行内格式化上下文中,盒子在包含块中从上到下水平地一个接一个地排列。这些盒子之间的水平外边距、边框和内边距都会被保留。盒子在垂直方向上可以以不同的方式对齐:它们的底部或顶部可以对齐,或者它们内部文本的基线可以对齐。包含形成一行的盒子的矩形区域称为行盒。” - 9.4.2
请注意,CSS 2.1 规范将文档描述为处于水平的、从上到下的书写模式。例如,通过描述块级框之间的垂直距离。在垂直书写模式下,块级元素和行级元素的行为是相同的;我们在流式布局和书写模式指南中探讨了这一点。
参与块格式化上下文的元素
在像英语这样的水平书写模式中,块级元素会垂直布局,一个在另一个下面。
在垂直书写模式中,它们将水平布局。
在本指南中,我们将使用英语,因此是水平书写模式。然而,如果你的文档是垂直书写模式,所描述的一切都应该以相同的方式工作。
正如规范中所定义的,两个块级框之间的外边距是创建元素之间分隔的原因。我们可以通过两个段落的布局看到这一点,我为它们添加了边框。默认的浏览器样式表通过为段落的顶部和底部添加外边距来增加它们之间的间距。
<div class="box">
<p>
One November night in the year 1782, so the story runs, two brothers sat
over their winter fire in the little French town of Annonay, watching the
grey smoke-wreaths from the hearth curl up the wide chimney. Their names
were Stephen and Joseph Montgolfier, they were papermakers by trade, and
were noted as possessing thoughtful minds and a deep interest in all
scientific knowledge and new discovery.
</p>
<p>
Before that night—a memorable night, as it was to prove—hundreds of millions
of people had watched the rising smoke-wreaths of their fires without
drawing any special inspiration from the fact.
</p>
</div>
p {
border: 2px solid green;
}
如果我们将段落元素的外边距设置为 0
,那么边框将会接触。
<div class="box">
<p>
One November night in the year 1782, so the story runs, two brothers sat
over their winter fire in the little French town of Annonay, watching the
grey smoke-wreaths from the hearth curl up the wide chimney. Their names
were Stephen and Joseph Montgolfier, they were papermakers by trade, and
were noted as possessing thoughtful minds and a deep interest in all
scientific knowledge and new discovery.
</p>
<p>
Before that night—a memorable night, as it was to prove—hundreds of millions
of people had watched the rising smoke-wreaths of their fires without
drawing any special inspiration from the fact.
</p>
</div>
p {
border: 2px solid green;
margin: 0;
}
默认情况下,块级元素会占据行内方向上的所有空间,所以我们的段落在其包含块内会尽可能地展开。如果我们给它们一个宽度,它们仍然会一个接一个地垂直布局——即使有空间让它们并排。每一个都将从包含块的起始边缘开始,也就是在该书写模式下句子开始的地方。
<div class="box">
<p>
One November night in the year 1782, so the story runs, two brothers sat
over their winter fire in the little French town of Annonay, watching the
grey smoke-wreaths from the hearth curl up the wide chimney. Their names
were Stephen and Joseph Montgolfier, they were papermakers by trade, and
were noted as possessing thoughtful minds and a deep interest in all
scientific knowledge and new discovery.
</p>
<p>
Before that night—a memorable night, as it was to prove—hundreds of millions
of people had watched the rising smoke-wreaths of their fires without
drawing any special inspiration from the fact.
</p>
</div>
p {
border: 2px solid green;
width: 40%;
}
外边距折叠
规范解释说,块级元素之间的外边距会合并。这意味着,如果你有一个带上外边距的元素紧跟着一个带下外边距的元素,那么总空间不是这两个外边距之和,而是外边距会合并,最终会变得和两个外边距中较大的那个一样大。
在下面的例子中,段落的上外边距为 20px
,下外边距为 40px
。段落之间的外边距大小为 40px
,因为第二个段落较小的上外边距与第一个段落较大的下外边距合并了。
<div class="box">
<p>
One November night in the year 1782, so the story runs, two brothers sat
over their winter fire in the little French town of Annonay, watching the
grey smoke-wreaths from the hearth curl up the wide chimney. Their names
were Stephen and Joseph Montgolfier, they were papermakers by trade, and
were noted as possessing thoughtful minds and a deep interest in all
scientific knowledge and new discovery.
</p>
<p>
Before that night—a memorable night, as it was to prove—hundreds of millions
of people had watched the rising smoke-wreaths of their fires without
drawing any special inspiration from the fact.
</p>
</div>
p {
border: 2px solid green;
margin: 20px 0 40px 0;
}
你可以在我们的文章掌握外边距合并中阅读更多关于外边距合并的内容。
注意: 如果你不确定外边距是否正在合并,请检查浏览器开发者工具中的盒模型值。这将为你提供外边距的实际大小,有助于你识别正在发生的情况。
参与行格式化上下文的元素
行级元素按照特定书写模式中句子的走向一个接一个地显示。虽然我们通常不认为行级元素有盒子,但和 CSS 中的所有东西一样,它们确实有。这些行级框一个接一个地排列。如果包含块中没有足够的空间容纳所有的框,一个框可以换到新的一行。创建的这些行被称为行盒。
在下面的例子中,我们有三个由一个段落和一个 <strong>
元素创建的行级框。
<p>
Before that night—<strong>a memorable night</strong>, as it was to
prove—hundreds of millions of people had watched the rising smoke-wreaths of
their fires without drawing any special inspiration from the fact.
</p>
在 <strong>
元素之前和 </strong>
元素之后的单词周围的框被称为匿名盒,这些框被引入以确保所有东西都被包裹在盒子里,但是我们不能直接选择它们。
行盒在块级方向上的尺寸(在英语中即高度)由其内部最高的盒子定义。在下一个例子中,<strong>
元素的字体大小为 300%;由于该内容跨越两行,它现在定义了这两行的行盒高度。
<p>
Before that night—<strong>a memorable night</strong>, as it was to
prove—hundreds of millions of people had watched the rising smoke-wreaths of
their fires without drawing any special inspiration from the fact.
</p>
strong {
font-size: 300%;
}
在我们的视觉格式化模型指南中了解更多关于块级和行级框的行为。
display 属性和流式布局
除了 CSS2.1 中存在的规则外,新级别的 CSS 进一步描述了块级和行级框的行为。display
属性定义了一个盒子及其内部任何盒子的行为。在 CSS Display Model Level 3 中,我们可以更多地了解 display
属性如何改变盒子及其生成的盒子的行为。
一个元素的显示类型定义了其外部显示类型;这决定了该盒子如何与同一格式化上下文中的其他元素一起显示。它还定义了内部显示类型,这决定了该元素内部的盒子如何行为。在考虑弹性布局时,我们可以非常清楚地看到这一点。在下面的例子中,我有一个 <div>
,我给它设置了 display: flex
。这个弹性容器的行为像一个块级元素:它显示在新的一行,并占据了行内方向上所有可用的空间。这是 block
的外部显示类型。
然而,弹性项目参与的是弹性格式化上下文,因为它们的父元素是带有 display: flex
的元素,其内部显示类型为 flex
,为直接子元素建立了弹性格式化上下文。
<div class="container">
<div>Flex Item</div>
<div>Flex Item</div>
<div>
<div>Children</div>
<div>are in</div>
<div>normal flow</div>
</div>
</div>
.container {
display: flex;
}
.container > * {
border: 1px solid green;
}
因此,你可以认为 CSS 中的每个盒子都以这种方式工作。盒子本身有一个外部显示类型,所以它知道如何与其他盒子一起表现。然后它有一个内部显示类型,这改变了其子元素的行为方式。这些子元素也同样有外部和内部显示类型。前面例子中的弹性项目变成了弹性级盒子,所以它们的外部显示类型是由它们作为弹性格式化上下文一部分的方式决定的。然而,它们的内部显示类型是流,这意味着它们的子元素参与常规流。除非有东西改变了它们的显示类型,否则我们弹性项目内部的嵌套项目会像块级和行级元素一样布局自己。
外部和内部显示类型的这个概念很重要,因为它告诉我们,一个使用像弹性盒子(display: flex
)和网格布局(display: grid
)这样的布局方法的容器,仍然在参与块级和行级布局,因为这些方法的外部显示类型是 block
。
更改元素参与的格式化上下文
浏览器根据对该元素通常有意义的方式,在块级或行级格式化上下文中显示项目。例如,<strong>
元素用于强烈强调一段内容,并且在浏览器中默认以粗体显示。让那个 <strong>
元素作为一个块级元素显示,换到新的一行,通常是没有意义的。如果你确实想让所有的 <strong>
元素都显示为块级框,你可以通过设置 strong { display: block; }
来做到。使用 CSS 为内容设置样式的能力意味着你总是可以使用最合适的语义化 HTML 元素来标记你的内容,然后用 CSS 来改变它们的显示方式。
<p>
Before that night—<strong>a memorable night</strong>, as it was to
prove—hundreds of millions of people had watched the rising smoke-wreaths of
their fires without drawing any special inspiration from the fact.
</p>
strong {
display: block;
}
总结
在本指南中,我们探讨了元素如何在常规流中作为块级和行级元素显示。由于这些元素的默认行为,一个没有任何 CSS 样式的 HTML 文档,将以可读的方式显示。通过理解常规流的工作原理,你会发现布局更容易,因为你理解了改变元素显示方式的起点。