1. 程式人生 > >CSS 中你應該瞭解的 BFC

CSS 中你應該瞭解的 BFC

我們常說的文件流其實分為定位流、浮動流和普通流三種。而普通流其實就是指BFC中的FC。FC是formatting context的首字母縮寫,直譯過來是格式化上下文,它是頁面中的一塊渲染區域,有一套渲染規則,決定了其子元素如何佈局,以及和其他元素之間的關係和作用。常見的FC有BFC、IFC,還有GFC和FFC。BFC是block formatting context,也就是塊級格式化上下文,是用於佈局塊級盒子的一塊渲染區域。

簡單來說,BFC 實際上是一塊區域,在這塊區域中遵循一定的規則,有一套獨特的渲染規則。

我們經常說的父級元素觸發了 BFC,實際上就是這個元素所在的區域要遵循 BFC 的渲染規則。

那麼 BFC 的渲染規則到底是什麼呢?

BFC 的原理是什麼(BFC 的渲染規則)

1)BFC 區域內的元素外邊距會發生重疊

這一點和外部的元素是一樣的,如果 BFC 內的相鄰元素或父子元素	滿足邊距重疊的條件也會發生重疊

2)BFC 區域內的元素不會與浮動元素重疊

BFC 內的元素不會與外部的浮動元素重疊

3)計算 BFC 區域的高度時,浮動元素也參與計算

清除浮動的原理,浮動元素也能撐開盒子,這也是為什麼說父元素觸發 BFC 後就可以解決父元素高度塌陷的	原因。

4)BFC 區域就相當於一個容器,內部的元素不會影響到外部,同樣外部的元素也不會影響到內部。

解決父子元素的外邊距重疊問題。

5)BFC 區域內部元素的排列和外部元素是一致的,也遵循塊元素佔一行,行內塊元素不佔一行等規則。

如何建立 BFC

平常說的觸發 BFC 是針對元素說的,元素觸發 BFC 後它所在的區域就變成了一個 BFC 區域,建立 BFC 是針對 BFC 本身來說的,因為它本身就是一個區域,所以用建立。

float 不為 none,浮動元素所在的區域就是一個 BFC 區域。

position 的值不是 static 或 relative 的元素所在的區域就是一個 BFC 區域

displaytable-cell 的表格單元格元素所在的區域也是一個 BFC 區域

overflow 不為 visible 的元素所在的區域也是一個 BFC 區域

下面是 MDN 列舉出來的,建立 BFC 的方式

  • 根元素(html) (html 元素所在的區域就是一個 BFC 區域,所以我們平時編寫的元素都是在一個 BFC 區域內渲染的,有很多東西為什麼要這樣應該有些也理解了)
  • 浮動元素(元素的 float 不是 none
  • 絕對定位元素(元素的 positionabsolutefixed
  • 行內塊元素(元素的 displayinline-block
  • 表格單元格(元素的 displaytable-cell,HTML表格單元格預設為該值)
  • 表格標題(元素的 displaytable-caption,HTML表格標題預設為該值)
  • 匿名錶格單元格元素(元素的 displaytable、``table-rowtable-row-group、``table-header-group、``table-footer-group(分別是HTML table、row、tbody、thead、tfoot的預設屬性)或 inline-table
  • overflow 值不為 visible 的塊元素
  • display 值為 flow-root 的元素
  • contain 值為 layoutcontent或 paint 的元素
  • 彈性元素(displayflexinline-flex元素的直接子元素)
  • 網格元素(displaygridinline-grid 元素的直接子元素)
  • 多列容器(元素的 column-countcolumn-width 不為 auto,包括 ``column-count1
  • column-spanall 的元素始終會建立一個新的BFC,即使該元素沒有包裹在一個多列容器中(標準變更,Chrome bug)。

BFC 規則驗證及應用

接下來根據上面列出的幾條規則,通過舉例一一驗證並且說明每條規則到底有什麼實際應用。

規則一 BFC 區域內的元素外邊距會發生重疊

BFC 區域內的元素和外部元素一樣如果滿足邊距重疊的條件也會發生邊距重疊。不知道你有沒有發現在 MDN 列舉出來的建立 BFC 的方法中,第一條就說 HTML 元素就是一個 BFC,所以我們在頁面上寫的元素實際上都是在 BFC 區域中。外部元素(其實也是在 BFC 區域內)會發生的事情,BFC 區域內的元素當然也會發生同樣的事情。

例如,下面的程式碼中,兩個 article 元素上邊距都為 10 px,下邊距都為 40 px,但是顯示在頁面上時發現兩個元素的邊距只有 40px,發生了邊距重疊,並且邊距值變成了較大的 40 px。

即使父元素 sec 觸發了 BFC,其內部的元素依然會發生邊距重疊,這也驗證了上面的 BFC 渲染規則中的第一條:BFC 區域內部的元素會發生邊距重疊。

  <section id = 'sec'>
    <style media="screen">
      #sec {
        background: yellowgreen;
        overflow: hidden;
      }
      .art1 {
        height: 100px;
        margin: 10px auto 40px;
        background: pink;
      }
      .art2 {
        height: 100px;
        margin: 10px auto 40px;;
        background: rgb(202, 24, 178);
      }
    </style>
    <article class='art1'>
    </article>
    <article class='art2'>
    </article>
  </section>

其實消除邊距重疊很簡單,只需要給 article2 一個父元素,然後觸發 BFC 即可。

  <section id = 'sec'>
    <style media="screen">
      #sec {
        background: yellowgreen;
        overflow: hidden;
      }
      .wrapper {
        overflow: hidden;
      }
      .art1 {
        height: 100px;
        margin: 10px auto 40px;
        background: pink;
      }
      .art2 {
        height: 100px;
        margin: 10px auto 40px;;
        background: rgb(202, 24, 178);
      }
    </style>
    <article class='art1'>
    </article>
    <div class='wrapper'>
      <article class='art2'>
      </article>
    </div>
  </section>

規則二 BFC 區域的元素不會與外部的浮動元素重疊

如下面的程式碼中,.art1 和 .art2 元素是相鄰的兩個元素。

.art1 是粉紅色向左浮動元素,.art2 元素會出現在浮動元素的下方和浮動元素重疊。

  <section id = 'sec'>
    <style media="screen">
      #sec {
        background: yellowgreen;
        overflow: hidden;
      }
      .wrapper {
        /* overflow: hidden; */
      }
      .art1 {
        float: left;
        height: 100px;
        width: 100px;
        background: pink;
      }
      .art2 {
        height: 200px;
        background: rgb(202, 24, 178);
      }
    </style>
    <article class='art1'>
    </article>
    <div class='wrapper'>
      <article class='art2'>
      </article>
    </div>
  </section>

現在我們讓 .art2 元素觸發 BFC,即給 .wrapper 元素加上 overflow: hidden.結果如下圖所示:

可以看到當將 art2 元素觸發 BFC 之後,它和浮動元素就不會重疊了。

規則三 計算 BFC 區域的高度時,浮動元素也參與計算(應用:清除浮動)

浮動帶來的問題主要就是父元素中的浮動元素不參與高度計算,所以導致父元素高度塌陷,這條規則使得浮動元素也參與到父元素的高度計算,因此這條規則也是清除浮動的原理。

現在令 .art1 元素左浮動。根據下圖可以看到,父元素 section 的高度為 0,這說明浮動元素並未參與高度計算。

  <section id = 'sec'>
    <style media="screen">
      #sec {
        background: yellowgreen;
      }
      .art1 {
        float: left;
      }
    </style>
    <article class='art1'>
      我是浮動元素
    </article>
  </section

現在令父元素 section 觸發 BFC(例如可以給父元素加一個 overflow: hidden 觸發 BFC),結果如下圖。

現在可以看到父元素有了高度。

規則四 BFC 區域就相當於一個容器,內部的元素不會影響到外部,同樣外部的元素也不會影響到內部(應用:消除邊距重疊)

.blue 元素的 margin-bottom 是 12px, .red-inner 元素的 margin-top 也為 10px。這個時候 ,如下圖所示,.blue 元素和 .red-outer 元素之間的 margin 為 12px,.red-inner 元素的 margin-top 並沒有起作用,發生了外邊距塌陷。

  <section id = 'sec'>
    <style>
      .blue {
        height: 50px;
        margin-bottom: 12px;
        background: blue;
      }
  
      .red-outer {
        background: red;
      }

      .red-inner {
        height: 50px;
        margin-top: 10px;
      }
    </style>
    <div class="blue">blue</div>
    <div class="red-outer">
      <div class="red-inner">red inner</div>
    </div>
  </section>

現在我們令 .red-outer 元素觸發 BFC(例如可以給父元素加一個 overflow: hidden 觸發 BFC),結果如下圖所示。

當觸發 BFC 之後,.red-outer 元素就是一塊 BFC 區域了,利用規則四,內部的元素和外部的元素相互不影響,.red-inner 元素是內部的元素,因此它不會再和父元素 .red-outer 的外邊距重合了(可以這樣理解 父元素的 margin 就是外部區域了)。所以現在它的 margin-top 10px 是相對於父元素的,由於父元素的寬度是由它撐開的,因此現在父元素的高度變成了 60px。

規則五 BFC 區域內部元素的排列和外部元素是一致的,也遵循塊元素佔一行,行內塊元素不佔一行等規則。

這個前面已經提到過了,在 MDN 觸發 BFC 的第一條就是 HTML 元素,可見 HTML 元素所在的區域就是一個 BFC 區域。因此 BFC 區域的內部元素和外部元素的行為是一致的,也遵循塊級元素獨佔一行,行內塊元素不佔一行等規則。

完,如果發現有什麼問題麻煩指正,非常感謝。