塊格式化上下文

塊格式化上下文(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
# 塊格式化上下文

另見