BFC(Block Formatting Context) 是Web頁面中盒模型佈局的CSS渲染模式。它的定位體系 屬於 常規文檔流 。摘自 W3C :javascript
浮動,絕對定位元素, inline-blocks
, table-cells
, table-captions
,和overflow
的值不爲 visible
的元素,(除了這個值已經被傳到了視口的時候)將建立一個新的 塊級格式化上下文
。css
上面的引述幾乎總結了一個 BFC 是怎樣造成的。可是讓咱們以另外一種方式來從新定義以便能更好的去理解。一個BFC是一個 HTML
盒子而且至少知足下列條件中的任何一個:html
float
的值不爲 none
position
的值不爲 static
或者 relative
display
的值爲 table-cell
, table-caption
, inline-block
, flex
, 或者 inline-flex
中的其中一個overflow
的值不爲 visible
一個BFC能夠被顯式的觸發。若是想要建立一個新的BFC,只須要給它添加上面提到的任何一個CSS樣式就能夠了。java
例如,請看下面的 HTML
:web
<div class="container">
Some Content here
</div>
一個新的BFC能夠經過給容器添加任何一個觸發BFC的CSS樣式,如 overflow: scroll
, overflow: hidden
, display: flex
, float: left
,或者 display: table
來建立。瀏覽器
display:table
可能會產生一些問題overflow:scroll
可能會顯示沒必要要的滾動條float:left
將會把元素置於容器的左邊,其餘元素環繞着它overflow:hidden
將會剪切掉溢出的元素因此每當想要建立一個新的BFC的時候,咱們會基於咱們的需求選擇最好的樣式條件。爲了一致性,我在這篇文章所給出的例子中所有使用了 overflow: hidden
less
container {
overflow: hidden;
}
你能夠自由使用除了 overflow: hidden
以外的樣式聲明。ide
W3C規範這樣描述:佈局
In a block formatting context, each box’s left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box’s line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).flex
在BFC中,每一個盒子的左外邊框緊挨着包含塊的左邊框(從右到左的格式,則爲緊挨右邊框)。即便存在浮動也是這樣的(儘管一個盒子的邊框會因爲浮動而收縮),除非這個盒子的內部建立了一個新的BFC浮動,盒子自己將會變得更窄)。
簡單來講,在上圖中咱們能夠看到,全部屬於同一個BFC的盒子都左對齊(左至右的格式),他們的左外邊框緊貼着包含塊的左邊框。在最後一個盒子裏咱們能夠看到儘管那裏有一個浮動元素(棕色)在它的左邊,另外一個元素(綠色)仍然緊貼着包含塊的左邊框。關於爲何會發生這種狀況的原理將會在下面的文字環繞部分進行討論。
在常規文檔流中,盒子都是從包含塊的頂部開始一個接着一個垂直堆放。兩個兄弟盒子之間的垂直距離是由他們個體的外邊距所決定的,但不是他們的兩個外邊距之和。
爲了去理解它,讓咱們來思考一下下面這個例子。
在上圖中咱們看到在紅色盒子(一個 div
)中包含兩個綠色的兄弟元素( p
元素),一個BFC已經被建立。
<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; }
理論上兩個兄弟元素之間的邊距應該是來兩個元素的邊距之和( 20px
),但它實際上爲 10px
。這就是被稱爲 外邊距摺疊 。當兄弟元素的外邊距不同時,將以最大的那個外邊距爲準。
這一開始聽起來可能有些困惑,由於咱們在前面討論了BFC致使外邊距摺疊的問題。但咱們必須牢記在心的是毗鄰塊盒子的垂直外邊距摺疊只有他們是在同一BFC時纔會發生。若是他們屬於不一樣的BFC,他們之間的外邊距將不會摺疊。因此經過建立一個新的BFC咱們能夠防止外邊距摺疊。
讓咱們在前面的例子中添加第三個兄弟元素,它的HTML將變爲:
<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; }
結果將會和上面的同樣。即,這將會有一個摺疊,三個兄弟元素將會以垂直距離爲10px
的距離分開。會這樣是由於三個 p
標籤都是屬於同一個BFC。
如今讓咱們來修改第三個兄弟元素使得它屬於另外一個新的BFC。它的HTML將變爲:
<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 */ }
如今,在輸出效果上將會有不一樣的地方:
當第二和第三個兄弟元素屬於不一樣的BFC時,在他們之間將不會有任何外邊距摺疊,在下面的DEMO中能很明顯看到。
一個BFC能夠包含浮動。不少時候咱們會碰到這種狀況,一個容器裏有浮動元素。因爲這個緣由,容器元素沒有高度,它的浮動孩子將會脫離頁面的常規流。咱們一般使用清除浮動來解決這個問題,最受歡迎的方法是使用一個 clearfix
的僞類元素。但咱們一樣能夠經過定義一個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; }
在上面的這個案例中,父容器將不會有任何的高度,它將不會包含已經浮動的子元素。爲了解決這個問題,咱們經過添加 overflow: hidden
,在容器中建立一個新的BFC。通過修改過的 CSS
爲:
.container { overflow: hidden; /* creates block formatting context */ background-color: green; } .container div { float: left; background-color: lightgreen; margin: 10px; }
如今,這個容器將包含浮動的子元素,它的高度將擴展到能夠包含它的子元素,在這個BFC,這些元素將會回到頁面的常規文檔流。
有時候一個浮動 div
周圍的文字環繞着它(以下圖中的左圖所示)可是在某些案例中這並非可取的,咱們想要的是外觀跟下圖中的右圖同樣的。爲了解決這個問題,咱們可能使用外邊距,可是咱們也可使用一個BFC來解決。
首先讓咱們理解文字爲何會環繞。爲此咱們須要知道當一個元素浮動時盒子模型是如何工做的。這就是我以前在討論BFC對齊時留下的那部分。讓咱們從下圖來了解發生了什麼。
圖中的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
元素的 line boxes
(指的是文本行)進行了移位。此處 line boxes
的水平收縮爲浮動元素提供了空間。
隨着文字的增長,由於 line boxes
再也不須要移位,最終將會環繞在浮動元素的下方,所以出現了那樣的狀況。這就解釋了爲何即便在浮動元素存在時,段落也將緊貼在包含塊的左邊框上,還有爲何 line boxes
會縮小以容納浮動元素。
若是咱們可以移動整個 p
元素,那麼這個環繞的問題就能夠解決了。
在去解決以前,讓咱們再回憶一下 W3C
標準上是怎麼描述的:
In a block formatting context, each box’s left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box’s line boxes may shrink due to the floats), unless the box establishes a new block formatting context (in which case the box itself may become narrower due to the floats).
在BFC中,每一個盒子的左外邊框緊挨着左邊框的包含塊(從右到左的格式化時,則爲右邊框緊挨)。即便在浮動裏也是這樣的(儘管一個盒子的邊框會由於浮動而萎縮),除非這個盒子的內部建立了一個新的BFC(這種狀況下,因爲浮動,盒子自己將會變得更窄),
根據這些,若是這個 p
元素建立了一個新的BFC,那麼它將不會緊挨着容器塊的左邊緣。這個能夠經過簡單的給 p
元素添加 overflow: hidden
來實現。這個方法建立了一個新的BFC解決了文字環繞在浮動元素周圍的問題。
若是咱們正在建立的一個多列布局佔滿了整個容器的寬度,在某些瀏覽器中最後一列有時候將會被擠到下一行。會發生這樣多是由於瀏覽器舍入(取整)了列的寬度使得總和的寬度超過了容器的寬度。然而,若是咱們在一個列的佈局中創建了一個新的BFC,它將會在前一列填充完以後的後面佔據所剩餘的空間。
讓咱們使用多列布局中的三列布局來做爲例子。
這是HTML代碼:
<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%; } .column:last-child { float: none; overflow: hidden; }
在CodePen 上DEMO的運行結果:
如今即便容器的寬度會有輕微的變化,可是佈局也不會中斷。固然,這並非多列布局的最好選擇,但它是防止最後一列下滑問題的一種方法。Flexbox在這種狀況下多是一個更好的解決方案,可是這應該要說明一下在這些狀況下元素是如何表現的。
我但願這篇文章已經向你展現了BFC的相關特性,以及他們如何影響元素在頁面上的視覺定位。全部的例子都展現了它們在實際案例中的應用,這應該會使得他們更加清晰。
若是你有任何東西想要補充,請在評論中讓咱們知道。若是你想要更深刻的討論的話,請務必在W3C上的 討論話題 中留言。
本文根據 @Ritesh Kumar 的《 Understanding Block Formatting Contexts in CSS 》所譯,整個譯文帶有咱們本身的理解與思想,若是譯得很差或有不對之處還請同行朋友指點。如需轉載此譯文,需註明英文出處:http://www.sitepoint.com/understanding-block-formatting-contexts-in-css/ 。