CSS布局中有一些概念,一旦你了解了它們,就能真正提高你的 CSS 布局能力。本文是關于塊格式化上下文(BFC)的。
你可能從未聽說過這個術語,但是如果你曾經用CSS做過布局,你可能知道它是什麼,了解什麼是 BFC,怎麼工作以及如何建立 BFC 非常有用?這些可以幫助你了解CSS中的布局是如何工作的。
在本文中,通過熟悉的示例來解釋什麼是 BFC。然後說明 display 的一個新值,隻有當你了解了什麼是 BFC 以及為什麼需要它時,它才有意義。

什麼是 BFC
在一個Web頁面的CSS渲染中,塊級格式化上下文 (Block Fromatting Context)是按照塊級盒子布局的。W3C對BFC的定義如下:
浮動元素和絕對定位元素,非塊級盒子的塊級容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不為“visiable”的塊級盒子,都會為他們的内容建立新的BFC(塊級格式上下文)。
BFC是一個獨立的布局環境,其中的元素布局是不受外界的影響,并且在一個 BFC 中,塊盒與行盒(行盒由一行中所有的内聯元素所組成)都會垂直的沿着其父元素的邊框排列。
塊格式化上下文(BFC)的行為通過一個簡單的float示例很容易了解。在下面的示例中,我有一個框,其中包含向左浮動的圖像和一些文本。如果我們有足夠多的文本,它會環繞浮動的圖像和邊框,然後環繞整個區域。
如果我删除了一些文本,那麼就沒有足夠的内容來包圍圖像,而且由于浮動被從文檔流中脫離,是以邊框會上升,并在圖像下方,直到文本的高度。
這是因為當我們浮動一個元素時,文本所在的框的寬度保持不變,為給浮動元素騰出空間而縮短的是文本的行框。這就是為什麼背景和邊框會出現在浮動後面的原因。
我們通常有兩種方法來解決這個布局問題。一種方法是使用 clearfix hack,它的作用是在文本和圖像下面插入一個元素,并将其設定為 clear:both。另一種方法是使用 overflow 屬性,其值不是預設值 visible。
檢視示範
overflow 以這種方式工作的原因是,使用 visible 的初值以外的任何值都會建立一個塊格式化上下文,而 BFC 的一個特性是它包含浮動。
BFC 是布局中的一個迷你布局
你可以将 BFC 看作是頁面内的一個迷你布局。一旦一個元素建立了一個 BFC,它就包含了所有的内容。正如我們所看到的,這包括浮動的元素,它們不再從盒子底部伸出來。BFC 還會導緻一些其他有用的行為。
BFC 可以防止 margin 折疊
了解邊距合并是另一個被低估的 CSS 技能。在下一個示例中,假設有一個背景顔色為灰色的 div。
這個 div 包含兩個标簽 p。外部 div 元素的 margin-bottom 為 40 像素,标簽 p 的頂部和底部 margin 都是 20 像素。
因為 p 元素的 margin 和外部 div 上的 margin 之間沒有任何東西,是以兩個會折疊,是以 p 最終與 div 的頂部和底部齊平。 我們在 p 的上方和下方看不到任何灰色。
在CSS當中,相鄰的兩個盒子(可能是兄弟關系也可能是祖先關系)的外邊距可以結合成一個單獨的外邊距。這種合并外邊距的方式被稱為折疊,并且因而所結合成的外邊距稱為折疊外邊距。折疊的結果按照如下規則計算:
- 兩個相鄰的外邊距都是正數時,折疊結果是它們兩者之間較大的值。
- 兩個相鄰的外邊距都是負數時,折疊結果是兩者絕對值的較大值。
- 兩個外邊距一正一負時,折疊結果是兩者的相加的和。
産生折疊的必備條件:margin必須是鄰接的!
如果我們把盒子設為 BFC,它現在包含了标簽 p 和它們的邊距,這樣它們就不會折疊,我們可以看到邊距後面容器的灰色背景。
檢視示範
再一次,BFC 的工作是把東西裝在盒子裡,防止它們從盒子裡跑出來。
BFC 可以阻止元素被浮動元素覆寫
你将熟悉 BFC 的這種行為,因為使用浮動的任何列類型布局都是這樣工作的。如果一個項目建立了一個 BFC,那麼該項目将不會包裹任何浮動元素。在下面的例子中,有如下 html 結構:
帶有 float 類的項被向左浮動,是以 div 中的文本在它環繞 float 之後。
我可以通過将包裹文本的 div 設定為 BFC 來防止這種包裹行為。
這實際上是我們建立具有多個列的浮動布局的方法。浮動項還為該項建立了一個 BFC,是以,如果右邊的列比左邊的列高,那麼我們的列就不會互相環繞。
檢視示範
在多列布局中使用 BFC
如果我們建立一個占滿整個容器寬度的多列布局,在某些浏覽器中最後一列有時候會掉到下一行。這可能是因為浏覽器四舍五入了列寬進而所有列的總寬度會超出容器。但如果我們在多列布局中的最後一列裡建立一個新的BFC,它将總是占據其他列先占位完畢後剩下的空間。
例如:
對應的CSS:
未建立 BFC 之前:
添加以下樣式建立一個 BFC:
現在盡管盒子的寬度稍有改變,但布局不會打破。當然,對多列布局來說這不一定是個好辦法,但能避免最後一列下掉。這個問題上彈性盒或許是個更好的解決方案,但這個辦法可以用來說明元素在這些環境下的行為。
還有什麼能建立 BFC?
除了使用 overflow 建立 BFC 外,其他一些 CSS 屬性還建立 BFC。正如我們所看到的,浮動元素建立了 BFC。你的浮動項将包含它裡面的任何東西。
使用以下方式都能建立 BFC
- float 的值不是 none。
- position 的值不是 static 或者 relative。
- display 的值是 inline-block、table-cell、flex、table-caption 或者inline-flex
- overflow 的值不是 visible
建立 BFC 的新方式
使用overflow或其他的方法建立BFC時會有兩個問題。首先,這些方法本身是有自身的設計目的,是以在使用它們建立BFC時可能會産生副作用。例如,使用overflow建立BFC後在某些情況下可能會看到出現一個滾動條或者元素内容被裁切。
這是由于overflow屬性的設計是用來讓你告訴浏覽器如何定義元素的溢出狀态的。浏覽器執行了它最基本的定義。
即使在沒有任何不想要的副作用的情況下,使用 overflow 也可能會讓其他開發人員感到困惑。為什麼 overflow 設定為 auto 或 scroll?最初的開發者的意圖是什麼?他們想要這個元件上的滾動條嗎?
最安全的做法應該是建立一個 BFC 時并不會帶來任何副作用,它内部的元素都安全的呆在這個迷你布局中,這種方法不會引起任何意想不到的問題,也可以了解開發者的意圖。CSS 工作組也十分認同這種想法,是以他們定制了一個新的屬性值:display:flow-root。
flow-root 浏覽器支援情況
你可以使用display:flow-root安全的建立BFC,來解決上文中提到的各種問題:包裹浮動元素、阻止外邊距疊加和阻止圍繞浮動元素。
浏覽器對該屬性的支援目前還是有限的,如果你覺得這個屬性值很友善,請投票去讓Edge也支援它。不過無論如何,你現在應該已經了解了什麼是 BFC,以及如何使用 overflow 或其他方法來包裹浮動,以及知道了 BFC 可以阻止元素去環繞浮動元素,如果你想使用彈性或網格布局可以在一些不支援他們的浏覽器中使用 BFC 的這些特性做降級處理。
了解浏覽器如何布置網頁是非常基礎的。 雖然有時看起來無關緊要,但是這些小知識可以加快建立和調試 CSS 布局所需的時間。