徹底搞懂 BFC

什麼是 BFC

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

除了 BFC,還有:html

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

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

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

塊級元素

CSS 屬性值 display 爲 block,list-item,table 的元素。佈局

塊級盒具備如下特性:flex

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

建立 BFC

如下元素會建立 BFCspa

  • 根元素(<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。3d

BFC 的特性

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

若是不太理解的,在下面 BFC 的應用我會說起。code

BFC 的應用

自適應兩列布局

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

/* 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等等,這些均可以觸發,不過父元素寬度表現不必定相同,但父元素高度都被撐出來了。固然實際運用可不是隨便挑一個走,仍是根據場景選擇。


相關文章
相關標籤/搜索