# [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`