一篇文章帶拿下盒模型BFC渲染機制

走在前端的大道上

本篇將自己讀過的相關 盒模型BFC 文章中,對自己有啓發的章節片段總結在這(會對原文進行刪改),會不斷豐富提煉總結更新。

一.常見定位方案

在講 BFC 之前,我們先來了解一下常見的定位方案,定位方案是控制元素的佈局,有三種常見方案:

  • 普通流 (normal flow)

    在普通流中,元素按照其在 HTML 中的先後位置至上而下佈局,在這個過程中,行內元素水平排列,直到當行被佔滿然後換行,塊級元素則會被渲染爲完整的一個新行,除非另外指定,否則所有元素默認都是普通流定位,也可以說,普通流中元素的位置由該元素在 HTML 文檔中的位置決定。

  • 浮動 (float)

    在浮動佈局中,元素首先按照普通流的位置出現,然後根據浮動的方向儘可能的向左邊或右邊偏移,其效果與印刷排版中的文本環繞相似。

  • 絕對定位 (absolute positioning)

    在絕對定位佈局中,元素會整體脫離普通流,因此絕對定位元素不會對其兄弟元素造成影響,而元素具體的位置由絕對定位的座標決定。

二、BFC 概念

Formatting context(格式化上下文) 是 W3C CSS2.1 規範中的一個概念。它是頁面中的一塊渲染區域,並且有一套渲染規則,它決定了其子元素將如何定位,以及和其他元素的關係和相互作用。常見的FC有BFC、IFC,還有GFC和FFC。

那麼 BFC 是什麼呢?

BFC 即 Block Formatting Contexts (塊級格式化上下文),它屬於上述定位方案的普通流。

一個BFC的範圍 包含創建該上下文元素的所有子元素,但不包括創建了新BFC的子元素的內部元素。這從另一方角度說明,一個元素不能同時存在於兩個BFC中。因爲如果一個元素能夠同時處於兩個BFC中,那麼就意味着這個元素能與兩個BFC中的元素髮生作用,就違反了BFC的隔離作用。

具有 BFC 特性的元素可以看作是隔離了的獨立容器,容器裏面的元素不會在佈局上影響到外面的元素,並且 BFC 具有普通容器所沒有的一些特性。

通俗一點來講,可以把 BFC 理解爲一個封閉的大箱子,箱子內部的元素無論如何翻江倒海,都不會影響到外部。

三、佈局規則

  1. 內部的Box會在垂直方向上一個接一個的放置
  2. 每個元素的左外邊距與包含塊的左邊界相接觸(從左向右),即使浮動元素也是如此。(這說明BFC中子元素不會超出他的包含塊,而position爲absolute的元素可以超出他的包含塊邊界)
  3. 屬於同一個BFC的 兩個相鄰Box的 上下margin會發生摺疊;
  4. BFC的區域不會與float的元素區域重疊(阻止元素被浮動元素覆蓋)
  5. 計算BFC的高度時,浮動子元素也參與計算(清除內部浮動)

四、觸發 BFC

只要元素滿足下面任一條件即可觸發 BFC 特性:

  1. body 根元素
  2. 浮動元素:float 除 none 以外的值,如left、right
  3. 絕對定位元素:position (absolute、fixed)
  4. display 爲 inline-block、table-cells、flex
  5. overflow 除了 visible 以外的值 ,如hidden、auto、scroll

注意:有些文章中說HTML可以觸發BFC,沒有說body,按照上邊介紹的一個BFC的範圍和下邊的案例1 來看,HTML能不能觸發不確定,但是body是可以的

五、BFC的特性及應用

1.普通流中兩個相鄰的塊元素 垂直方向上的 margin會摺疊

<style>
.p {  
  width:200px;  
  height:50px;  
  margin:50px 0;  
  background-color:red;  
}  
</style>

<body>
   <div class="p"></div>  
   <div class="p"></div>  
</body>

效果圖是:

clipboard.png

發生外邊距摺疊,是因爲他們 同屬於 body這個根元素
讓 它們 不屬於同一個BFC,就能避免外邊距摺疊:

<style>
.wrap {  
  overflow:hidden;  
}
.p {  
  width:200px;  
  height:50px;  
  margin:50px 0;  
  background-color:red; 
}
</style>

<body>
    <div class="p"></div>  
    
    <div class="wrap">  
      <div class="p"></div>  
    </div> 
</body>  

效果圖是:

clipboard.png

2.普通流中 父子嵌套關係的2個塊元素 垂直方向上的 margin會摺疊

    <style>
        .father {
            width: 200px;
            height: 200px;
            background: skyblue;
        }
        
        .son {
            width: 100px;
            height: 100px;
            background: red;
        }
    </style>
  
    <body>
        <div class="father">
            <div class="son"></div>
        </div>
    </body>

clipboard.png

然後,我們給子元素添加一個margin-top: 50px時

.son {
    width: 100px;
    height: 100px;
    background: red;
    margin-top: 50px;
}

我們神奇的發現父子元素同時"掉下來了50px",如圖所示

clipboard.png

3.BFC可以包含浮動的元素(清除浮動)

正常情況下,浮動的元素會脫離普通文檔流,所以下面的代碼裏:

<style>
.wrap {  
  border: 1px solid #000; 
}
.inner {  
  float: left;
  width: 50px;
  height: 50px; 
  background: #eee;
}
</style>

<body>
    <div class="wrap">
        <div class="inner"></div>
    </div>
</body>  

外層的div會無法包含 內部浮動的div,效果見下圖:

clipboard.png

但如果我們 觸發外部容器的BFC,根據BFC規範 計算BFC的高度時,浮動元素也參與計算,那麼外部div容器就可以包裹着浮動元素,所以只要把代碼修改如下:

<style>
.wrap {  
  border: 1px solid #000; 
  overflow:hidden;  
}
.inner {  
  float: left;
  width: 50px;
  height: 50px; 
  background: #eee;
}
</style>

<body>
    <div class="wrap">
        <div class="inner"></div>
    </div>
</body>  

就可以完成以下效果:

clipboard.png

4.實現2欄自適應佈局

要求左側固定300px,右側自適應的佈局

 <style>
        .wrapper, * {
            padding: 0;
            margin: 0;
        }

        .left {
            width: 300px;
            height: 100px;
            background: red;
            float: left;
        }

        .right {
            height: 100px;
            background: skyblue;
            overflow: hidden;
        }

    </style>
    
    <div class="wrapper">
        <div class="left">left</div>
        <div class="right">right</div>
    </div>

clipboard.png

原理:BFC元素不會和浮動的元素重疊

參考文章:
10 分鐘理解 BFC 原理
CSS中重要的BFC
淺析CSS裏的 BFC 和 IFC
前端人人都應該理解的盒模型BFC渲染機制

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章