---
# System prepended metadata

title: '[IM005] - BFC (Block Formatting Context)'
tags: [CSS, ironman]

---

# [IM005] - BFC (Block Formatting Context)

> **前言**
> 2020 秋天，我將用 30 天的時間，來嘗試回答和網路前端開發相關的 30 個問題。30 天無法一網打盡浩瀚的前端知識，有些問題可能對有些讀者來說相對簡單，不過期待這趟旅程，能幫助自己、也幫助讀者打開不同的知識大門。有興趣的話，跟著我一起探索吧！
> 

## BFC (Block Formatting Context)

在閱讀 CSS 相關文章時，應該偶爾會看到有人提到 BFC (Block Format Context)，但其實過去從來也沒有認真搞懂過什麼是 BFC，就趁這個機會來深入探究一下吧！

## Definition(s)

首先，先來看看 [W3C]() 當中關於 "formatting context" 的解釋：

> A formatting context is the environment into which a set of related boxes are laid out. Different formatting contexts lay out their boxes according to different rules. 

當我們在談到 "formatting context" 的時候，其實就在談論該環境下 "boxes" 將如何排列。所以常見的 formatting context 有
* block formatting context
* inline formatting context
* grid formatting context
* flex formatting context

如果有一點 HTML 和 CSS 的經驗的話，看到上面這些，應該很快就會猜想到他們代表著截然不同的排列方式。這裡我們不會深入介紹所有的 formatting context，只會來看最基本（可能也最為重要的）block formatting context.

接下來，我們來看看 [W3C](https://www.w3.org/TR/CSS2/visuren.html#normal-flow) 上關於 BFC 的說明：

> In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.

在 BFC 當中，boxes 會是垂直、一個接著一個的排列，兩個 boxes 之間的距離是由 margin 來決定，但是在垂直方向上的 margin，會有重疊的現象產生。

而 [MDN](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context) 上的說明是：
> A block formatting context is a part of a visual CSS rendering of a web page. It's the region in which the layout of block boxes occurs and in which floats interact with other elements.

> Formatting contexts affect layout, but typically, we create a new block formatting context for the positioning and clearing floats rather than changing the layout, because an element that establishes a new block formatting context will:
> 
> * contain internal floats.
> * exclude external floats.
> * suppress margin collapsing.

BFC 是當瀏覽器渲染網頁的時所建立出來的區域（環境），也就是 block boxes 佈局的區域，以及浮動元素與其他元素互動的區域。BFC 會影響到網頁的佈局，新建立的 BFC 將可以
* 包含內部浮動元素
* 排除（不管）外部浮動元素
* 解決 margin collapsing 的狀況

看到這裡，大概知道 BFC 會自動生成，但是後面提到三個新建 BFC 可以做到的事情又是什麼意思呢？

簡單來說，就是當我們刻意創造一個新的 BFC 出來之後，就可以改變原先的佈局方式，特別是與浮動元素的互動，以及 margin collapsing 的狀況。

接下來，就讓我們來看看三種行為的例子吧！

## [New BFC] 1. Contain internal floats

當一個元素新建立的 BFC 之後，其內部空間的大小（這裡特別指高度）將會包含浮動元素的高度。舉例來說，這裡有一個元素 `id="wrapper"`，當中有兩個元素， `id="one" ` 和 `id="two"`，其中因為 `id="one"` 為浮動元素，所以整個 `id=wrapper` 的大小會等同於 `id=two` 的大小。

```htmlmixed=
<!-- html -->
<div>
  <div class="wrapper" id="wrapper">
    <div class="float" id="one">Float Left</div>
    <div class="box" id="two">Box</div>
  </div>
</div>
```
```css
/* css */
.wrapper {
  background-color: yellow;
  border: 3px solid black;
}

.float {
  float: left;
  width: 200px;
  height: 100px;
  background-color: rgba(255, 255, 255, .5);
  border:1px solid black;
  padding: 10px;
}
```
![Imgur](https://i.imgur.com/3i3s4ms.png)

不過如果我們在 `id="wrapper"` 當中新增 `overflow: auto` 的屬性，那麼他自己本身就會建立一個新的 BFC ，使得整個元素的高度，也會包含當中浮動元素的高度！
```css
/* css */
.wrapper {
  background-color: yellow;
  border: 3px solid black;
  overflow: auto;              /* 創造出新的 BFC */
}
```
![Imgur](https://i.imgur.com/nDWKHJd.png)

##  [New BFC] 2. Exclude external floats

當建立一個新的 BFC 之後，就會排除其外、原本需要和浮動元素互動的狀況。舉例來說，假設在一個 div 當中有兩個 boxes，其中一個有設定 float 如下：
```htmlmixed=
<!-- html -->
<div>
  <div class="float" id="one">Float left</div>
  <div class="box" id="two">Box</div>
</div>
```
```css
/* css */
.box {   
    background-color: yellow;   
    border: 3px solid black; 
    height: 50px;
} 

.float {   
    float: left;
    overflow: hidden;
    resize: both;
    margin-right: 25px;
    width: 200px;   
    height: 100px;   
    background-color: rgba(255, 255, 255, .5);   
    border: 1px solid black;   
    padding: 10px; 
}
```
![Imgur](https://i.imgur.com/Ub5RhSb.png)
<!-- ![Imgur](https://i.imgur.com/ZOMq9Yk.gifv) -->

會發現 `id="one"` 的 box 會覆蓋在 `id="two"` box 之上。

如果我們在 `id="two"` 額外設定
```css
/* css */
#two { display: flow-root }
```
![Imgur](https://i.imgur.com/UT0sBm2.png)
<!-- ![Imgur](https://i.imgur.com/NPUD2rE.gifv) -->
就會發現兩個 boxes 就分開來不會重疊。這是因為我們幫 `id="two"` 的 box 建立了新的 BFC，離開了它原本所在的 BFC（需要考慮和浮動元素互動的 BFC），因此就會排除了和外部浮動元素的交互作用，也就沒有覆蓋的狀況發生。

## [New BFC] 3. Suppress margin collapsing

在本文的最一開始，有提到關於垂直方向 margin 重疊的現象。舉例來說，如果今天這裡有兩個 boxes 分別為
```htmlmixed=
<!-- html -->
<div class="box" id="one">one</div>
<div class="box" id="two">two</div>
```
同時我們也定義 
```css
/* css */
.box { margin: 10px }
```
會發現上下兩個 boxes 實際的距離，是 10px 而不是 20px! 原因是這兩個 boxes 目前都在同一個 BFC 當中。若要想要排除這樣的狀況，我們可以刻意創造另外一個 BFC 如下
```htmlmixed=
<!-- html -->
<div class="box" id="one">one</div>
<!-- 創造出新的 BFC -->
<div class="wrapper">                
  <div class="box" id="two">two</div>
</div>

```
```css
/* css */
.box { margin: 10px }
.wrapper { overflow: hidden }  /* 創造出新的 BFC */
```
就會發現兩個 boxes 之間的距離變寬了，即為 20px!

看完上面的三種行為，就會發現，當我們了解了 BFC 的行為後，其實就可以幫助我們快速調整佈局，避免不想要的狀況出現。

## How to create new BFC?

前面提到的 BFC 的特型，像是當中的 boxes 會如何排列，以及當我們刻意創造新的 BFC 之後，會產生什麼樣的改變。最後，就讓我們很快來看一下如何創造 BFC：

1.  root element of the doc (`<html>`): root 本身就會建立 BFC。如果沒有子元素沒有建立自己的 BFC 或 IFC，那麼所有的子元素也都在同一個 BFC 當中。
2.  float 不為 `none` 的元素
3.  position 為 `absolute` 或 `fixed`
4.  display 為 `inline-block`
6.  display 為 `flow-root`
7.  display 為 `flex` 或 `inline-flex`
8.  display 為 `grid` 或 `inline-grid`
9.  Block element 且 overflow 不為 `visible`

以上為較為常見的佈局方法，想知道其他可以創造新的 BFC 的佈局，可以參考 MDN 的說明。

## Ending

這篇文章簡單了介紹 BFC 以及使用上所帶來的影響，雖然有些現象過去已經知道，甚至很習慣了，不過多瞭解一點背後運作的道理，也許對於這些現象的印象就會更為深刻。


### Ref:
* [BFC (W3C)](https://www.w3.org/TR/css-display-3/#bfc)
* [Block formatting context (MDN)](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context)
* [Understanding CSS Layout And The Block Formatting Context](https://www.smashingmagazine.com/2017/12/understanding-css-layout-block-formatting-context/)

***
> **TD**
> 在北緯一度努力踏上軟體工程師之路的物理人，對世界運作的方式充滿好奇
> *"Life is like riding a bicycle. To keep your balance, you must keep moving."*
> [More about me](https://tsungtingdu.github.io/profile/)

***

###### tags: `ironman` `CSS`