译者的话
这是我找到讲解 格式化上下文 (Block Formatting Context, BFC) 最棒的文章之一(下文统称 BFC ),由于 BFC 困扰我良久,希望这篇翻译能让 BFC 不再困扰大家。
翻译是机翻 + 修改,会有删减,另外强烈推荐阅读原文。
原文地址:www.smashingmagazine.com/2017/12/und…
导读
你可能从没听过“块格式化上下文”,但是如果你曾经用CSS做过布局,你可能就知道它是什么。本文将会讲述如何创建块格式化上下文,以及为什么它在CSS布局中很重要,并向展示创建块格式化上下文的新方法。
有些概念一旦理解会确确实实增加你的CSS技能熟练度,而理解 BFC 以及知道如何创建 BFC 非常有用,可以帮助加深对CSS布局的理解。这篇文章会有丰富且常见的例子帮助你理解 BFC ,并解释为什么你需要 BFC 。
什么是BFC?
只要通过一个简单的浮动布局的例子就可以理解 BFC 的行为。在下面的示例中,有一个 div ,div 里包含一个 向左浮动的div 和 一些文本 。如果文本足够多,就会环绕浮动元素,然后环绕整个区域。
<div class="outer">
<div class="float">I am a floated element.</div>
I am text inside the outer box.
</div>
.outer {
border: 5px dotted rgb(214,129,137);
border-radius: 5px;
width: 450px;
padding: 10px;
margin-bottom: 40px;
}
.float {
padding: 10px;
border: 5px solid rgba(214,129,137,.4);
border-radius: 5px;
background-color: rgba(233,78,119,.4);
color: #fff;
float: left;
width: 200px;
margin: 0 20px 0 0;
}
- 文本环绕着浮动元素

如果删除一些文本内容,那么就没有足够的内容来包围浮动元素,而且由于浮动是脱离文档流的,所以边框高度会变矮,只有到包含到文本的高度。即高度坍塌。
- 如果没有足够的文本,外部元素的边框就不会考虑浮动元素所需的高度

这是因为当我们浮动一个元素时,文本所在的框的宽度保持不变,为了给浮动元素腾出空间而缩短的是文本的空间。
我们通常有两种方法来解决这个布局问题。一种方法是使用 clearfix hack(即清除浮动),它的作用是在文本和图像下面插入一个元素,并将其设置为 clear: both; 。另一种方法是使用 overflow 属性,将其值改为 visible 以外的即可。
.outer {
overflow: auto;
}
- 使用
overflow: auto令外部的div包含浮动元素

另外,可以在CODEPEN中查看效果:codepen.io/rachelandre…
overflow 以这种方式工作的原因是,使用 除visible初值以外 的任何值都会创建一个 BFC ,而 BFC 的特性之一就是它可以包裹浮动元素。
译者注:重点之一, BFC 可以包裹浮动元素。即让浮动元素 看起来没有脱离文档流一样 ,占据着其宽高大小的位置。
BFC 其实是你的布局中的mini布局
可以把 BFC 想象成页面内的迷你布局。一旦一个元素创建了一个 BFC ,所有的东西都包含在它里面。正如我们所看到的,包括浮动元素,它们不再从盒子的底部伸出。 BFC 也会有一些其他有用的行为。
BFC可以防止外边距塌陷
理解边距坍塌是另一个被低估的CSS技能。在下一个示例中,有一个背景颜色为灰色的div。
这个div包含两个段落。外部div元素的页边距离底部40像素;段落的上下边距边都是20像素。
.outer {
background-color: #ccc;
margin: 0 0 40px 0;
}
p {
padding: 0;
margin: 20px 0 20px 0;
background-color: rgb(233,78,119);
color: #fff;
}
由于p元素的页边距与外部div的页边距之间没有任何内容,这两个元素将折叠起来,因此段落最终与框的顶部和底部齐平。我们在段落的上面和下面没有看到灰色背景。
- 边距塌陷,所以我们看不到框的顶部和底部是灰色的

如果我们为外部div元素创建一个 BFC ,它就会包含段落和它们的边距,这样它们就不会折叠,我们可以看到边距后面容器的灰色背景。
.outer {
background-color: #ccc;
margin: 0 0 40px 0;
overflow: auto; /* 创建BFC,参考:https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Block_formatting_context */
}
- 对于BFC容器,外边距不会坍塌

在CODEPEN中查看代码:codepen.io/rachelandre…
(译者注:在理解BFC之前,我都是在外部元素里设置padding实现同样的效果!)
再次说明, BFC 的工作是把东西装在盒子里,并且防止它们从盒子里跑出来。
BFC 可以让内容不再包裹浮动元素。您还将熟悉 BFC 的这种行为,因为使用浮动的任何列类型布局都是这样工作的。
如果一个项创建了一个 BFC ,那么该项目将不会包裹任何浮动元素。在下面的例子中,有这样的标记:
<div class="outer">
<div class="float">I am a floated element.</div>
<div class="text">I am text</div>
</div>
带有 float类 的项会向左浮动,因此div中的文本在它环绕 float 之后。
- 文本包围浮动元素

我们可以通过将包裹文本的div设置为BFC来防止这种环绕行为。
.text {
overflow: auto;
}
- 包含
text类的div现在是BFC,因此文本不会换行

这实际上就是创建多个列浮动布局的方法。浮动项还为该项创建了一个BFC,因此,就算右边的列比左边的列高,各个列也不会相互环绕。
在CODEPEN中查看代码:codepen.io/rachelandre…
还有什么方法能创建BFC?
除了使用 overflow 创建 BFC 外,其他一些CSS属性还创建 BFC 。正如我们所看到的,浮动元素创建了 BFC 。你的浮动项将包含它里面的任何东西。
在元素中使用position: absolute 或者 position: fixed
使用 display: inline-block 、 display: table-cell 或 display: table- title 。表单元格和表标题是这些HTML元素的默认设置,因此,如果有一个 table ,每个单元格都将创建一个 BFC。
使用 column-span: all ,用于跨多列布局的列。 Flex 和 Grid 的项还创建了类似于 BFC 的东西,只不过它们分别被描述为 Flex格式化上下文(Flex Formatting Context, FFC) 和 网格格式化上下文(Grid Formatting Context, GFC) 。这反映了每个项参与的布局类型。 块格式化上下文BFC 表示项正在参与块布局,而 Flex格式化上下文 表示项正在参与Flex布局。在实际中,结果是相同的,浮动也可以被包含并且元素的 margin 边界不会坍塌。
创建BFC的新方法
使用 overflow 或其他方法创建 BFC 有两个问题。首先,这些方法的副作用是基于它们真正的设计目的。 overflow 方法创建一个 BFC 并包含浮动元素,但是在某些情况下,你会发现你得到了一个不需要的滚动条,或者阴影被剪切了。这是因为设计 overflow 属性的目的是让您告诉浏览器在溢出的情况下应该做什么——导致滚动条或剪切内容。浏览器正在做你让它做的事情!
即使在没有任何不想要的副作用的情况下,使用 overflow 也可能会让其他开发人员感到困惑。为什么 overflow 设置为自动或滚动?最初的开发者的意图是什么?他们想要这个组件上的滚动条吗?
另一个非常有用的创建 BFC 的方法是令其是惰性的,除了创建那个小布局和在其中安全地发生事情的能力之外,不会导致其他行为。该方法不会引起任何意外的问题,并且允许清楚地说明开发人员的意图。CSS工作组认为这可能也非常方便,因此我们有了 display 属性的一个新值—— flow-root 。
如果您有一个支持 display: flow-root (如最新的Firefox或Chrome)的浏览器,您可以在下面的代码页中看到所有这些。
CODEPEN代码页面:codepen.io/rachelandre…
display: flow-root的浏览器支持情况

浏览器对这个属性的支持是有限的,但支持还在增加,如果你认为它会很方便,一定要去给它投票。但是,即使你现在不能在代码中使用方便的 flow-root 特性,你现在也了解了什么是 BFC ,以及当你使用 overflow 或其他方法来包裹浮动元素时可以清楚的知道你在做什么。
你已经了解了关于浏览器如何布局web页面的一些非常基本的知识。虽然它们本身看起来无关紧要,但正是这些小知识可以加快创建和调试CSS布局所需的时间。