块格式化上下文

块格式化上下文(Block Formatting Context,BFC)是网页 CSS 视觉渲染的一部分。它是块级盒布局发生的区域,也是浮动元素与其他元素交互的区域。

块格式化上下文由以下至少一种方式创建:

  • 文档的根元素(<html>)。
  • 浮动元素(float 值不为 none 的元素)。
  • 绝对定位元素(position 值为 absolutefixed 的元素)。
  • 行内块元素(display: inline-block 的元素)。
  • 表格单元格(display: table-cell 的元素,HTML 表格单元格的默认值)。
  • 表格标题(display: table-caption 的元素,HTML 表格标题的默认值)。
  • display 值为 tabletable-rowtable-row-grouptable-header-grouptable-footer-group(分别是 HTML table、tr、tbody、thead、tfoot 的默认值)或 inline-table 的元素隐式创建的匿名表格单元格。
  • overflow 值不为 visibleclip 的块级元素。
  • display: flow-root 的元素。
  • <button> 元素和 <input> 按钮类型,其 display 默认为 flow-root
  • contain 值为 layoutcontentpaint 的元素。
  • 弹性项(display 值为 flexinline-flex 的元素的直接子元素),如果它们本身不是弹性网格表格容器。
  • 网格项(display 值为 gridinline-grid 的元素的直接子元素),如果它们本身不是弹性网格表格容器。
  • 多列容器(column-countcolumn-width 不为 auto 的元素,包括 column-count: 1 的元素)。
  • column-span: all 的元素,即使该元素未被包含在多列容器中。

格式化上下文会影响布局,因为一个建立新的块格式化上下文的元素将会:

通过将元素的 display 设置为 flexgridinline-flexinline-grid 定义的弹性容器和网格容器,会建立一个新的弹性或网格格式化上下文。这些上下文与块格式化上下文类似,不同之处在于弹性或网格容器内没有浮动的子元素,但这些格式化上下文确实会排除外部浮动并抑制外边距折叠。

示例

让我们看几个例子,来了解创建 BFC 的效果。

包含内部浮动

在下面的例子中,我们有一个浮动内容,它与旁边的内容高度相同。我们有一个浮动元素在一个带有 border<div> 内部。该 <div> 的内容浮动在浮动元素的旁边。由于浮动元素的内容比旁边的内容高,<div> 的边框现在穿过了浮动元素。正如文档流内外元素指南中所解释的,浮动元素已经脱离了文档流,所以 <div>backgroundborder 只包含其内容,而不包含浮动元素。

使用 overflow: auto

设置 overflow: auto 或将 overflow 设置为除初始值 visible 以外的其他值,会创建一个新的 BFC 来包含浮动。我们的 <div> 现在变成了我们布局中的一个“迷你布局”。任何子元素都将被包含在其中。

使用 overflow 创建 BFC 的问题在于,overflow 属性本意是告诉浏览器如何处理溢出的内容。在某些情况下,当你纯粹为了创建 BFC 而使用此属性时,你可能会发现出现不想要的滚动条或被裁剪的阴影。此外,对于未来的开发者来说,代码可读性可能会降低,因为他们可能不清楚你为何为此目的使用 overflow。如果你使用 overflow,最好在代码中添加注释进行解释。

使用 display: flow-root

display: flow-root 值使我们能够创建一个新的 BFC,而不会产生任何其他潜在的有问题的副作用。在包含块上使用 display: flow-root 会创建一个新的 BFC。

<div> 上应用 display: flow-root; 后,该容器内的所有内容都参与该容器的块格式化上下文,浮动元素不会从元素底部溢出。

当你理解了你正在创建的东西,在为其内部的流式布局创建新上下文方面,其行为类似于 root 元素(浏览器中的 <html> 元素)时,flow-root 这个值名就很有意义了。

这是 <button> 元素和 <input> 按钮类型的默认渲染方式,这意味着只要按钮的 display 值没有被设置为一个不会自动创建 BFC 的值,它就会创建一个新的 BFC。

HTML

html
<section>
  <div class="box1">
    <div class="float">I am a floated box!</div>
    <p>I am content inside the container.</p>
  </div>
</section>
<section>
  <div class="box2">
    <div class="float">I am a floated box!</div>
    <p>I am content inside the <code>overflow:auto</code> container.</p>
  </div>
</section>
<section>
  <div class="box3">
    <div class="float">I am a floated box!</div>
    <p>I am content inside the <code>display:flow-root</code> container.</p>
  </div>
</section>

CSS

css
section {
  height: 150px;
}
.box1 {
  background-color: rgb(224 206 247);
  border: 5px solid rebeccapurple;
}
.box2,
.box3 {
  background-color: aliceblue;
  border: 5px solid steelblue;
}
.box2 {
  overflow: auto;
}
.box3 {
  display: flow-root;
}
.float {
  float: left;
  width: 200px;
  height: 100px;
  background-color: rgb(255 255 255 / 50%);
  border: 1px solid black;
  padding: 10px;
}

排除外部浮动

在下面的示例中,我们使用 display: flow-root 和浮动,创建了两个并排的盒子,演示了一个处于正常流中的元素建立了一个新的 BFC,并且不会与和该元素本身在同一个块格式化上下文中的任何浮动元素的外边距盒重叠。

HTML

html
<section>
  <div class="float">Try to resize this outer float</div>
  <div class="box"><p>Normal</p></div>
</section>
<section>
  <div class="float">Try to resize this outer float</div>
  <div class="box2">
    <p><code>display:flow-root</code></p>
  </div>
</section>

CSS

css
section {
  height: 150px;
}
.box {
  background-color: rgb(224 206 247);
  border: 5px solid rebeccapurple;
}
.box2 {
  background-color: aliceblue;
  border: 5px solid steelblue;
  display: flow-root;
}
.float {
  float: left;
  overflow: hidden; /* required by resize:both */
  resize: both;
  margin-right: 25px;
  width: 200px;
  height: 100px;
  background-color: rgb(255 255 255 / 75%);
  border: 1px solid black;
  padding: 10px;
}

阻止外边距折叠

你可以创建一个新的 BFC 来避免两个相邻元素之间的外边距折叠

外边距折叠示例

在这个例子中,我们有两个相邻的 <div> 元素,它们各自有一个 10px 的垂直外边距。由于外边距折叠,它们之间的垂直间隙是 10px,而不是我们可能期望的 20px

html
<div class="blue"></div>
<div class="red"></div>
css
.blue,
.red {
  height: 50px;
  margin: 10px 0;
}

.blue {
  background: blue;
}

.red {
  background: red;
}

阻止外边距折叠

在这个例子中,我们将第二个 <div> 包裹在一个外部 <div> 中,并通过在外部 <div> 上使用 overflow: hidden 来创建一个新的 BFC。这个新的 BFC 阻止了嵌套的 <div> 的外边距与外部 <div> 的外边距发生折叠。

html
<div class="blue"></div>
<div class="outer">
  <div class="red"></div>
</div>
css
.blue,
.red {
  height: 50px;
  margin: 10px 0;
}

.blue {
  background: blue;
}

.red {
  background: red;
}

.outer {
  overflow: hidden;
  background: transparent;
}

规范

规范
CSS Display Module Level 3
# 块格式化上下文

另见