在一個Web頁面的CSS渲染中,塊級格式化上下文 (Block Fromatting Context)是按照塊級盒子佈局的。W3C對BFC的定義以下:css
浮動元素和絕對定位元素,非塊級盒子的塊級容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不爲「visiable」的塊級盒子,都會爲他們的內容建立新的BFC(塊級格式上下文)。
爲了便於理解,咱們換一種方式來從新定義BFC。一個HTML元素要建立BFC,則知足下列的任意一個或多個條件便可:html
一、float的值不是none。
二、position的值不是static或者relative。
三、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
四、overflow的值不是visible瀏覽器
BFC是一個獨立的佈局環境,其中的元素佈局是不受外界的影響,而且在一個BFC中,塊盒與行盒(行盒由一行中全部的內聯元素所組成)都會垂直的沿着其父元素的邊框排列。app
要顯示的建立一個BFC是很是簡單的,只要知足上述4個CSS條件之一就行。例如:ide
<div class="container"> 你的內容 </div>
在類container中添加相似 overflow: scroll,overflow: hidden,display: flex,float: left,或 display: table 的規則來顯示建立BFC。雖然添加上述的任意一條都能建立BFC,但會有一些反作用:佈局
一、display: table 可能引起響應性問題
二、overflow: scroll 可能產生多餘的滾動條
三、float: left 將把元素移至左側,並被其餘元素環繞
四、overflow: hidden 將裁切溢出元素flex
於是不管何時須要建立BFC,都要基於自身的須要來考慮。對於本文,將採用 overflow: hidden 方式:ui
.container { overflow: hidden; }
如前文所說,在一個BFC中,塊盒與行盒(行盒由一行中全部的內聯元素所組成)都會垂直的沿着其父元素的邊框排列。W3C給出得規範是:this
在BFC中,每個盒子的左外邊緣(margin-left)會觸碰到容器的左邊緣(border-left)(對於從右到左的格式來講,則觸碰到右邊緣)。浮動也是如此(儘管盒子裏的行盒子 Line Box 可能因爲浮動而變窄),除非盒子建立了一個新的BFC(在這種狀況下盒子自己可能因爲浮動而變窄)。
常規流佈局時,盒子都是垂直排列,二者之間的間距由各自的外邊距所決定,但不是兩者外邊距之和。lua
<div class="container"> <p>Sibling 1</p> <p>Sibling 2</p> </div>
對應的CSS:
.container { background-color: red; overflow: hidden; /* creates a block formatting context */ } p { background-color: lightgreen; margin: 10px 0; }
渲染結果如圖:
在上圖中,一個紅盒子(div)包含着兩個兄弟元素(p),一個BFC已經建立了出來。
理論上,兩個p元素之間的外邊距應當是兩者外邊距之和(20px)但實際上倒是10px,這是外邊距摺疊(Collapsing Margins)的結果。
在CSS當中,相鄰的兩個盒子(多是兄弟關係也多是祖先關係)的外邊距能夠結合成一個單獨的外邊距。這種合併外邊距的方式被稱爲摺疊,而且於是所結合成的外邊距稱爲摺疊外邊距。摺疊的結果按照以下規則計算:
一、兩個相鄰的外邊距都是正數時,摺疊結果是它們二者之間較大的值。
二、兩個相鄰的外邊距都是負數時,摺疊結果是二者絕對值的較大值。
三、兩個外邊距一正一負時,摺疊結果是二者的相加的和。
產生摺疊的必備條件:margin必須是鄰接的! (對於不產生摺疊的狀況,見參考文章的連接)
BFC可能形成外邊距摺疊,也能夠利用它來避免這種狀況。BFC產生外邊距摺疊要知足一個條件:兩個相鄰元素要處於同一個BFC中。因此,若兩個相鄰元素在不一樣的BFC中,就能避免外邊距摺疊。
改進前面的例子:
<div class="container"> <p>Sibling 1</p> <p>Sibling 2</p> <p>Sibling 3</p> </div>
對應的CSS:
.container { background-color: red; overflow: hidden; /* creates a block formatting context */ } p { background-color: lightgreen; margin: 10px 0; }
結果和上面同樣,因爲外邊距摺疊,三個相鄰P元素之間的垂直距離是10px,這是由於三個 p 標籤都從屬於同一個BFC。
修改第三個P元素,使之建立一個新的BFC:
<div class="container"> <p>Sibling 1</p> <p>Sibling 2</p> <div class="newBFC"> <p>Sibling 3</p> </div> </div>
對應的CSS:
.container { background-color: red; overflow: hidden; /* creates a block formatting context */ } p { margin: 10px 0; background-color: lightgreen; } .newBFC { overflow: hidden; /* creates new block formatting context */ }
如今的結果如圖:
由於第二個和第三個P元素如今分屬於不一樣的BFC,它們之間就不會發生外邊距摺疊了。
浮動元素是會脫離文檔流的(絕對定位元素會脫離文檔流)。若是一個沒有高度或者height是auto的容器的子元素是浮動元素,則該容器的高度是不會被撐開的。咱們一般會利用僞元素(:after或者:before)來解決這個問題。BFC能包含浮動,也能解決容器高度不會被撐開的問題。
看個例子:
<div class="container"> <div>Sibling</div> <div>Sibling</div> </div>
CSS:
.container { background-color: green; } .container div { float: left; background-color: lightgreen; margin: 10px; }
在上面這個例子中,容器沒有任何高度,而且它包不住浮動子元素,容器的高度並不會被撐開。爲解決這個問題,能夠在容器中建立一個BFC:
.container { overflow: hidden; /* creates block formatting context */ background-color: green; } .container div { float: left; background-color: lightgreen; margin: 10px; }
如今容器能夠包住浮動子元素,而且其高度會擴展至包住其子元素,在這個新的BFC中浮動元素又迴歸到頁面的常規流之中了。
如上圖所示,對於浮動元素,可能會形成文字環繞的狀況(Figure1),但這並非咱們想要的佈局(Figure2纔是想要的)。要解決這個問題,咱們能夠用外邊距,但也能夠用BFC。
First let us understand why the text wraps. For this we have to understand how the box model works when an element is floated. This is the part I left earlier while discussing the alignment in a block formatting context. Let us understand what is happening in Figure 1 in the diagram below:
假設HTML是:
<div class="container"> <div class="floated"> Floated div </div> <p> Quae hic ut ab perferendis sit quod architecto, dolor debitis quam rem provident aspernatur tempora expedita. </p> </div>
上圖整個黑色區域表示 p 元素。p 元素沒有移位但它疊在了浮動元素之下,而p元素的文本(行盒子)卻移位了,行盒子水平變窄來給浮動元素騰出了空間。隨着文本的增長,最後文本將環繞在浮動元素之下,由於那時候行盒子再也不須要移位,也就成了圖Figure1的樣子。
再回顧一下W3C的描述:
在BFC上下文中,每一個盒子的左外側緊貼包含塊的左側(從右到左的格式裏,則爲盒子右外側緊貼包含塊右側),甚至有浮動也是如此(儘管盒子裏的行盒子 Line Box 可能因爲浮動而變窄),除非盒子建立了一個新的BFC(在這種狀況下盒子自己可能因爲浮動而變窄)。
於是,若是p元素建立一個新的BFC那它就不會再緊貼包含塊的左側了。
若是咱們建立一個佔滿整個容器寬度的多列布局,在某些瀏覽器中最後一列有時候會掉到下一行。這多是由於瀏覽器四捨五入了列寬從而全部列的總寬度會超出容器。但若是咱們在多列布局中的最後一列裏建立一個新的BFC,它將老是佔據其餘列先佔位完畢後剩下的空間。
例如:
<div class="container"> <div class="column">column 1</div> <div class="column">column 2</div> <div class="column">column 3</div> </div>
對應的CSS:
.column { width: 31.33%; background-color: green; float: left; margin: 0 1%; } /* Establishing a new block formatting context in the last column */ .column:last-child { float: none; overflow: hidden; }
如今儘管盒子的寬度稍有改變,但佈局不會打破。固然,對多列布局來講這不必定是個好辦法,但能避免最後一列下掉。這個問題上彈性盒或許是個更好的解決方案,但這個辦法能夠用來講明元素在這些環境下的行爲。