博客 / 詳情

返回

完全搞懂 BFC

什麼是 BFC

BFC 全稱是 Block Formatting Context,即塊格式化上下文。

除了 BFC,還有:

  • IFC(行級格式化上下文)- inline 內聯
  • GFC(網格佈局格式化上下文)- display: grid
  • FFC(自適應格式化上下文)- display: flexdisplay: inline-flex
注意:同一個元素不能同時存在於兩個 BFC 中

它是 Web 頁面的可視 CSS 渲染的一部分,是塊盒子的佈局過程發生的區域,也是浮動元素與其他元素交互的區域。怎麼理解呢?實際就是説 BFC 是一個渲染區域,並且有自己的一套渲染規則,使其內部佈局的元素具有一些特性。

BFC 提供一個獨立的佈局環境,BFC 內部的元素佈局與外部互不影響。

塊級元素

CSS 屬性值 display 為 block,list-item,table 的元素。

塊級盒具有以下特性:

  • CSS 屬性值 display 為 block,list-item,table 時,它就是塊級元素
  • 佈局上,塊級盒呈現為豎直排列的塊
  • 每個塊級盒都會參與 BFC 的創建
  • 每個塊級元素都會至少生成一個塊級盒,稱為主塊級盒;一些元素可能會生成額外的塊級盒,比如 <li>,用來存放項目符號

創建 BFC

以下元素會創建 BFC

  • 根元素(<html>
  • 浮動元素(float不為none
  • 絕對定位元素(positionabsolutefixed
  • 表格的標題和單元格(displaytable-captiontable-cell
  • 匿名錶格單元格元素(displaytableinline-table
  • 行內塊元素(displayinline-block
  • overflow 的值不為 visible 的元素
  • 彈性元素(displayflexinline-flex 的元素的直接子元素)
  • 網格元素(displaygridinline-grid 的元素的直接子元素)

以上是 CSS2.1 規範定義的 BFC 觸發方式,在最新的 CSS3 規範中,彈性元素和網格元素會創建 F(Flex)FC 和 G(Grid)FC。

BFC 的特性

  • BFC 是頁面上的一個獨立容器,容器裏面的子元素不會影響外面的元素。
  • BFC 內部的塊級盒會在垂直方向上一個接一個排列
  • 同一 BFC 下的相鄰塊級元素可能發生外邊距摺疊,創建新的 BFC 可以避免外邊距摺疊
  • 每個元素的外邊距盒(margin box)的左邊與包含塊邊框盒(border box)的左邊相接觸(從右向左的格式的話,則相反),即使存在浮動
  • 浮動盒的區域不會和 BFC 重疊
  • 計算 BFC 的高度時,浮動元素也會參與計算

如果不太理解的,在下面 BFC 的應用我會提及。

BFC 的應用

自適應兩列布局

左列浮動(定寬或不定寬都可以),給右列開啓 BFC。

/* html 代碼 */
<div>
    <div class="left">浮動元素,無固定寬度</div>
    <div class="right">自適應</div>
</div>

/* css 代碼 */
* {
    margin: 0;
    padding: 0;
}
.left {
    float: left;
    height: 200px;
    margin-right: 10px;
    background-color: red;
}
.right {
    overflow: hidden;
    height: 200px;
    background-color: yellow;
}

  1. 將左列設為左浮動,將自身高度塌陷,使得其它塊級元素可以和它佔據同一行的位置。
  2. 右列為 div 塊級元素,利用其自身的流特性佔滿整行。
  3. 右列設置overflow: hidden,觸發 BFC 特性,使其自身與左列的浮動元素隔離開,不佔滿整行。

這即是上面説的 BFC 的特性之一:浮動盒的區域不會和 BFC 重疊

防止外邊距(margin)重疊

兄弟元素之間的外邊距重疊

/* html 代碼 */
<div>
    <div class="child1"></div>
    <div class="child2"></div>
</div>

/* css 代碼 */
* {
    margin: 0;
    padding: 0;
}
.child1 {
    width: 100px;
    height: 100px;
    margin-bottom: 10px;
    background-color: red;
}
.child2 {
    width: 100px;
    height: 100px;
    margin-top: 20px;
    background-color: green;
}

兩個塊級元素,紅色 div 距離底部 10px,綠色 div 距離頂部 20px,按道理應該兩個塊級元素相距 30px 才對,但實際卻是取距離較大的一個,即 20px。

塊級元素的上外邊距和下外邊距有時會合並(或摺疊)為一個外邊距,其大小取其中的較大者,這種行為稱為外邊距摺疊(重疊),注意這個是發生在屬於同一 BFC 下的塊級元素之間

根據 BFC 特性,創建一個新的 BFC 就不會發生 margin 摺疊了。比如我們在他們兩個 div 外層再包裹一層容器,加屬性overflow: hidden,觸發 BFC,那麼兩個 div 就不屬於同個 BFC 了。

/* html 代碼 */
<div>
    <div class="parent">
        <div class="child1"></div>
    </div>
    <div class="parent">
        <div class="child2"></div>
    </div>
</div>

/* css 代碼 */
.parent {
    overflow: hidden;
}
/* ... */

這個關於兄弟元素外邊距疊加的問題,除了觸發 BFC 也有其他方案,比如你統一隻用上邊距或下邊距,就不會有上面的問題。

父子元素的外邊距重疊

這種情況存在父元素與其第一個或最後一個子元素之間(嵌套元素)。
如果在父元素與其第一個/最後一個子元素之間不存在邊框、內邊距、行內內容,也沒有創建塊格式化上下文、或者清除浮動將兩者的外邊距 分開,此時子元素的外邊距會“溢出”到父元素的外面。

如下代碼:

/* HTML 代碼 */
<div id="parent">
  <div id="child"></div>
</div>

/* CSS 代碼 */
* {
    margin: 0;
    padding: 0;
}
#parent {
    width: 200px;
    height: 200px;
    background-color: green;
    margin-top: 20px;
}
#child {
    width: 100px;
    height: 100px;
    background-color: red;
    margin-top: 30px;
}

如上圖,紅色的 div 在綠色的 div 內部,且設置了margin-top為 30px,但我們發現紅色 div 的頂部與綠色 div 頂部重合,並沒有距離頂部 30px,而是溢出到父元素的外面計算。即本來父元素距離頂部只有 20px,被子元素溢出影響,外邊距重疊,取較大的值,則距離頂部 30px。

解決辦法:

  1. 給父元素觸發 BFC(如添加overflow: hidden
  2. 給父元素添加 border
  3. 給父元素添加 padding

這樣就能實現我們期望的效果了:

清除浮動解決令父元素高度坍塌的問題

當容器內子元素設置浮動時,脱離了文檔流,容器中總父元素高度只有邊框部分高度

/* html 代碼 */
<div class="parent">
  <div class="child"></div>
</div>

/* css 代碼 */
* {
    margin: 0;
    padding: 0;
}
.parent {
    border: 4px solid red;
}
.child {
    float: left;
    width: 200px;
    height: 200px;
    background-color: blue;
}

解決辦法:給父元素觸發 BFC,使其有 BFC 特性:計算 BFC 的高度時,浮動元素也會參與計算

.parent {
    overflow: hidden;
    border: 4px solid red;
}

上面我們都是用的overflow: hidden觸發 BFC,因為確實常用嘛,但是觸發 BFC 也不止是隻有這一種方法,如上面寫的所示。

比如可以設置float: left; float: right; display: inline-block; overflow: auto; display: flex; display:" table; positionabsolutefixed等等,這些都可以觸發,不過父元素寬度表現不一定相同,但父元素高度都被撐出來了。當然實際運用可不是隨便挑一個走,還是根據場景選擇。


  • ps: 個人技術博文 Github 倉庫,覺得不錯的話歡迎 star,鼓勵我繼續寫作吧~
user avatar jidongdehai_co4lxh 頭像 hightopo 頭像 coderleo 頭像 _raymond 頭像 susouth 頭像 gaoming13 頭像 tingzhong666 頭像 lidalei 頭像 clearlove07 頭像 caideheirenyagao 頭像 dashan_5c230d1ae1f9e 頭像 ran_agppr 頭像
19 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.