深刻理解BFC和Margin Collapse

BFC的理解與應用

由於BFC的理解對咱們徹底地弄懂margin collapse是不可缺乏的。因此讓咱們先來認識一下BFC。html

首先咱們來看看w3c規範對BFC的解釋,其實對於這種概念的學習上,咱們老是建議首先尋找官方的定義,由於原則上來講官方的纔是最權威和正確的,並且還比較詳細,千萬不要由於看到英文就畏懼不前。app

什麼是BFC(Block formatting contexts)

w3c規範中的BFC定義

浮動元素和絕對定位元素,非塊級盒子的塊級容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不爲「visiable」的塊級盒子,都會爲他們的內容建立新的BFC(塊級格式上下文)。佈局

在BFC中,盒子從頂端開始垂直地一個接一個地排列,兩個盒子之間的垂直的間隙是由他們的margin 值所決定的。在一個BFC中,兩個相鄰的塊級盒子的垂直外邊距會產生摺疊。學習

在BFC中,每個盒子的左外邊緣(margin-left)會觸碰到容器的左邊緣(border-left)(對於從右到左的格式來講,則觸碰到右邊緣)。網站

BFC的通俗理解:

首先BFC是一個名詞,是一個獨立的佈局環境,咱們能夠理解爲一個箱子(其實是看不見摸不着的),箱子裏面物品的擺放是不受外界的影響的。轉換爲BFC的理解則是:BFC中的元素的佈局是不受外界的影響(咱們每每利用這個特性來消除浮動元素對其非浮動的兄弟元素和其子元素帶來的影響。)而且在一個BFC中,塊盒與行盒(行盒由一行中全部的內聯元素所組成)都會垂直的沿着其父元素的邊框排列。spa

BFC的運用

在w3c的規範中,除了上面的一段定義以外,BFC的相關知識點分佈地比較零散,但基本集中在float、絕對定位、margin collaspe中。下面咱們來看看如何應用到BFC來解決問題。code

在不少網站中,咱們常常會看到這樣的一種,左邊圖片+右邊信息的兩欄結構,下面咱們來看看如何利用BFC來實現。orm

首先咱們給出這樣的結構:htm

1 .box {width:210px;border: 1px solid #000;float: left;}
2 .img {width: 100px;height: 100px;background: #696;float: left;}
3 .info {background: #ccc;color: #fff;}
1 <div class="box">
2     <div class="img">image</div>
3     <p class="info">信息信息信息信息信息信息信息信息信息信息信息信</p>
4 </div>

通常狀況下它呈現出咱們所樂意看到的樣子:blog

但隨着文字信息增多後,會變地很是的糟糕:

很明顯,這是由於info類裏面的文字受到了浮動元素的影響,但這並非咱們所指望的。此時咱們能夠爲P元素的內容創建一個BFC,讓其內容消除對外界浮動元素的影響。根據上文所知,只要給info元素添加overflow:hidden;便可爲其內容創建新的BFC。固然你也能夠經過其餘方法來創建。其效果以下:

合併外邊距與BFC

在CSS當中,相鄰的兩個盒子(多是兄弟關係也多是祖先關係)的外邊距能夠結合成一個單獨的外邊距。這種合併外邊距的方式被稱爲摺疊,而且於是所結合成的外邊距稱爲摺疊外邊距。

摺疊的結果:

  1. 兩個相鄰的外邊距都是正數時,摺疊結果是它們二者之間較大的值。
  2. 兩個相鄰的外邊距都是負數時,摺疊結果是二者絕對值的較大值。
  3. 兩個外邊距一正一負時,摺疊結果是二者的相加的和。

產生摺疊的必備條件:margin必須是鄰接的!

而根據w3c規範,兩個margin是鄰接的必須知足如下條件:

  • 必須是處於常規文檔流(非float和絕對定位)的塊級盒子,而且處於同一個BFC當中。
  • 沒有線盒,沒有空隙(clearance,下面會講到),沒有padding和border將他們分隔開
  • 都屬於垂直方向上相鄰的外邊距,能夠是下面任意一種狀況
    • 元素的margin-top與其第一個常規文檔流的子元素的margin-top
    • 元素的margin-bottom與其下一個常規文檔流的兄弟元素的margin-top
    • height爲auto的元素的margin-bottom與其最後一個常規文檔流的子元素的margin-bottom
    • 高度爲0而且最小高度也爲0,不包含常規文檔流的子元素,而且自身沒有創建新的BFC的元素的margin-top和margin-bottom

以上的條件意味着下列的規則:

  • 建立了新的BFC的元素(例如浮動元素或者'overflow'值爲'visible'之外的元素)與它的子元素的外邊距不會摺疊
  • 浮動元素不與任何元素的外邊距產生摺疊(包括其父元素和子元素)
  • 絕對定位元素不與任何元素的外邊距產生摺疊
  • inline-block元素不與任何元素的外邊距產生摺疊
  • 一個常規文檔流元素的margin-bottom與它下一個常規文檔流的兄弟元素的margin-top會產生摺疊,除非它們之間存在間隙(clearance)。
  • 一個常規文檔流元素的margin-top 與其第一個常規文檔流的子元素的margin-top產生摺疊,條件爲父元素不包含 padding 和 border ,子元素不包含 clearance。
  • 一個 'height' 爲 'auto' 而且 'min-height' 爲 '0'的常規文檔流元素的 margin-bottom 會與其最後一個常規文檔流子元素的 margin-bottom 摺疊,條件爲父元素不包含 padding 和 border ,子元素的 margin-bottom 不與包含 clearance 的 margin-top 摺疊。
  • 一個不包含border-top、border-bottom、padding-top、padding-bottom的常規文檔流元素,而且其 'height' 爲 0 或 'auto', 'min-height' 爲 '0',其裏面也不包含行盒(line box),其自身的 margin-top 和 margin-bottom 會摺疊。

(下面咱們對不產生摺疊的狀況逐一分析。)

浮動和絕對定位不與任何元素產生 margin 摺疊

緣由:浮動元素和絕對定位元素不與其餘盒子產生外邊距摺疊是由於元素會脫離當前的文檔流,違反了上面所述的兩個margin是鄰接的條件同時,又由於浮動和絕對定位會使元素爲它的內容建立新的BFC,所以該元素和子元素所處的BFC是不相同的,所以也不會產生margin的摺疊。

DEMO:

 1 * {padding:0;margin: 0; text-align: center;}
 2 .wrapper {margin:30px;width: 450px;border:1px solid red;}
 3 .small-box {width: 50px;height: 50px;margin: 10px;background: #9cc;}
 4 .middle-box {width: 100px;height: 100px;margin: 20px;background: #99c;}
 5 .big-box {width: 120px;height: 120px;margin: 20px;background: #33e;}
 6 .floatL {float: left;}
 7 .floatR {float: right;}
 8 .clear {clear: both;}
 9 .posA {position: absolute;}
10 .overHid{overflow: hidden;}
11 .red {background: #f00;}
12 .green {background: #0f0;}
13 .blue {background: #00f;}
1 <div class="wrapper overHid">
2     <div class="big-box blue">non-float</div>
3     <div class="middle-box green floatL">
4         <div class="small-box red"></div>
5         float left
6     </div>
7 </div>

 

可是浮動元素脫離了當前的BFC並不影響它後面的兄弟元素,後面的兄弟元素與浮動元素前面的元素依然在同一個BFC當中,因此,它們之間的margin仍是會摺疊的。下面咱們對上面的demo作一下修改:

1 <div class="wrapper overHid">
2     <div class="big-box">non-float</div>
3     <div class="middle-box green floatL">float left</div>
4     <div class="middle-box red">non-clear</div>
5 </div>

從上面這個修改後的demo中能夠看出,紅色的塊盒在沒有清楚浮動的狀況下,它的margin-top和藍色塊盒的margin-bottom產生了摺疊,這證實了我上面的結論。

下面咱們來談談 'clearance' 這個神奇的東西,當浮動元素以後的元素設置clear以閉合相關方向的浮動時,根據w3c規範規定,閉合浮動的元素會在其margin-top以上產生必定的空隙(clearance,以下圖),該空隙會阻止元素margin-top的摺疊,並做爲間距存在於元素的margin-top的上方。關於這個間距的計算稍微有點複雜,但實際工做中你並不須要去計算它,咱們先來看看例子吧:

1 <div class="wrapper overHid">
2     <div class="big-box" style="box-shadow:0 20px 0 rgba(0,0,255,0.2);">non-float</div>
3     <div class="middle-box green floatL" style="opacity:0.6">float left</div>
4     <div class="middle-box red clear" style="margin-top:40px;box-shadow:0 -40px 0 rgba(255,0,0,0.2);">clear</div>
5 </div>

上面的圖中咱們能夠看到,咱們爲紅色塊盒設置的40px的margin-top(這裏咱們經過相同高度的陰影來將其可視化)好像並無對紫色塊盒起做用,並且不管咱們怎麼修改這個margin-top值都不會影響紅色塊盒的位置,而只由綠色塊盒的margin-bottom所決定。

也就是說,咱們只須要知道,閉合浮動的元素的border-top會緊貼着相應的浮動元素的margin-bottom。

原來,經過w3c的官方規範可知,閉合浮動的塊盒在margin-top上所產生的間距(clearance)的值與該塊盒的margin-top之和應該足夠讓該塊盒垂直的跨越浮動元素的margin-bottom,使閉合浮動的塊盒的border-top剛好與浮動元素的塊盒的margin-bottom相鄰接。

用上圖例子中的相關值能夠得出這樣一個式子:r-margin-top + r-clearance = g-margin-top + g-height + g-margin-bottom

PS!閉合浮動並不能使浮動元素回到原來的BFC當中!

分析二:inline-block元素與其兄弟元素、子元素和父元素的外邊距都不會摺疊(包括其父元素和子元素)

inline-block不符合w3c規範所說元素必須是塊級盒子的條件,由於規範中又說明,塊級盒子的display屬性必須是如下三種之一:'block', 'list-item', 和 'table'。

參考資料

相關文章
相關標籤/搜索