英文:Ritesh Kumar
譯文:HaoyCn
網址:http://segmentfault.com/a/1190000003068557#articleHeader0
塊級格式化背景關係(Block Formatting Context)是網頁CSS視覺渲染的一部分,並用於決定塊盒子的佈局。在定位體系(Positioning Scheme)中它屬於常規流(Normal Flow)。根據W3C所言:
浮動、絕對定位元素(position 為 absolute 或 fixed)、行內塊元素 display:inline-block、表格單元格display:table-cell、表格標題 display:table-caption 以及 overflow 屬性值不為 visible 的元素(除了該值被傳播到視點 viewport 的情況)將建立一個新的塊級格式化背景關係。
上面的引言差不多總結了一個BFC是如何形成的。但讓咱們用另外一種更通俗易懂的方式來重定義它。一個BFC就是一個HTML盒子,它至少滿足以下條件之一:
- float 的值不為 none
- position 的值不為 static 或 relative
- display 的值為 table-cell、table-caption、inline-block、flex 或 inline-flex
- overflow 的值不為 visiable
建立一個塊級格式化背景關係
一個BFC可以顯式觸發。如果我們想建立之,我們只需給它新增上面提到的任何一個CSS樣式。
比如,看下麵的HTML:
Some Content here
一個新的BFC可以透過給容器新增任意一個必要的CSS樣式來建立,比如overflow: scroll,overflow: hidden,display: flex,float: left,或 display: table。儘管上述條件都可以建立BFC,但也會產生一些其他效果,如:
- display: table 可能引發響應性問題
- overflow: scroll 可能產生多餘的捲軸
- float: left 將把元素移至左側,並被其他元素環繞
- overflow: hidden 將裁切上限溢位元素
所以無論何時,當要建立一個BFC時,我們要基於需求選擇最恰當的樣式。為了保持一致性,我在本文的所有例子中均使用overflow: hidden。
.container {
overflow: hidden;
}
你可以自由選擇使用除 overflow: hidden 之外的其他樣式。
BFC中盒子的對齊
W3C規範道:
在BFC背景關係中,每個盒子的左外側緊貼包含塊的左側(從右到左的格式裡,則為盒子右外側緊貼包含塊右側),甚至有浮動也是如此(儘管盒子裡的行盒子 Line Box 可能由於浮動而變窄),除非盒子建立了一個新的BFC(在這種情況下盒子本身可能由於浮動而變窄)。
簡單來說,如上圖所示,所以屬於BFC的盒子都左對齊(在從左到右的格式下)並且它們的左外側緊貼包含塊的左側。在最後一個盒子中我們可以看到儘管左側存在一個浮動元素(棕色),另外一個元素(綠色)仍然緊貼包含塊的左側。該情況的產生原理將在下文關於文字環繞的部分中討論。
BFC造成的外邊距摺疊
在常規流中,盒子從包含塊的頂部開始一個個地垂直擺放。兩個同胞盒子間的垂直舉例由兩個盒子各自的外邊距所決定,但不是二者外邊距之和。
為便於理解,我們看個例子。
在上圖中,一個紅盒子(div)包含著兩個同胞綠元素(p),一個BFC已經建立了出來。
Sibling 1
Sibling 2
相應的CSS是:
.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
background-color: lightgreen;
margin: 10px 0;
}
理論上兩個同胞元素間的外邊距應當是二者外邊距之和(20px)但實際上卻是10px。這就是眾所周知的外邊距摺疊(Collapsing Margins)。如果同胞元素外邊距不同,將應用最大的那個。
使用BFC避免外邊距摺疊
在討論了上面BFC摺疊外邊距的情況後,現在說避免摺疊可能有點讓人摸不著頭腦。但我們必須牢記於心的一件事是,相鄰塊級盒子(同胞)之間的垂直外邊距只有在它們處於同一個BFC時才會發生摺疊。如果它們分屬於不同的BFC,就不會摺疊了。所以,透過建立新的BFC我們可以避免外邊距摺疊。
讓我們在早前的例子中新增第三個同胞元素,現在HTML是:
Sibling 1
Sibling 2
Sibling 3
CSS是:
.container {
background-color: red;
overflow: hidden; /* creates a block formatting context */
}
p {
background-color: lightgreen;
margin: 10px 0;
}
結果和上面一樣,即是說,摺疊還是會發生並且三個同胞間分隔的垂直距離是10px。這是因為三個 p 標簽都從屬於同一個BFC。
現在我們修改第三個同胞元素,使之成為一個新的BFC的一部分。現在的HTML變成了:
Sibling 1
Sibling 2
Sibling 3
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,它們之間就不會發生外邊距摺疊了。
使用BFC包含浮動
BFC可以包含浮動。我們經常遇到容器中含有浮動元素的情況。這種情況下容器元素沒有高度並且其浮動子元素脫離了網頁的常規流。我們通常用清除浮動解決這個問題,最普遍的做法就是使用偽元素。但我們也可以透過建立一個BFC來解決問題。
看個例子:
SiblingSibling
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中浮動元素又回歸到頁面的常規流之中了。
使用BFC避免文字環繞
有時候浮動DIV旁邊的文字會環繞它(如下圖1所示)而這種情況有時候並不如我們所願,我們想要下圖2的效果。要解決這個問題,我們可以用外邊距,但也可以用BFC。
首先讓我們弄明白為何文字會環繞。要理解這個我們必須明白,當存在元素浮動的時候,盒模型如何工作。這就是我早先討論BFC中對齊時候的遺留問題。我們透過下圖來看圖1到底發生了什麼。
假設HTML是:
Floated div
Quae hic ut ab perferendis sit quod architecto,
dolor debitis quam rem provident aspernatur tempora
expedita.
上圖整個黑色區域表示 p 元素,如我們所見,p 元素沒有移位但它疊在了浮動元素之下,而p元素的行盒子(即文字行)卻移位了,行盒子水平變窄來給浮動元素騰出了空間。
隨著文字的增加,最後文字將環繞在浮動元素之下,因為那時候行盒子不再需要移位,也就成了圖1的樣子。這就是為什麼即便有浮動元素,段落仍緊貼包含塊的左側,而行盒子會變窄來給浮動元素騰位子。
如果我們能位移整個 p 元素,這個環繞問題也就迎刃而解了。
在說解決方案之前,我們再回顧下W3C規範:
在BFC背景關係中,每個盒子的左外側緊貼包含塊的左側(從右到左的格式裡,則為盒子右外側緊貼包含塊右側),甚至有浮動也是如此(儘管盒子裡的行盒子 Line Box 可能由於浮動而變窄),除非盒子建立了一個新的BFC(在這種情況下盒子本身可能由於浮動而變窄)。
據此,如果 p 元素建立一個新的BFC那它就不會再緊貼包含塊的左側了。給 p 元素新增 overflow: hidden 就能輕而易舉地辦到。這解決了文字環繞浮動物件的問題。
在多列佈局中使用BFC
如果我們建立一個佔滿整個容器寬度的多列佈局,在某些瀏覽器中最後一列有時候會掉到下一行。這可能是因為瀏覽器四捨五入了列寬從而所有列的總寬度會超出容器。但如果我們在多列佈局中的最後一列裡建立一個新的BFC,它將總是佔據其他列先佔位完畢後剩下的空間。
我們來舉個三列佈局的例子:
這是HTML:
column 1column 2column 3
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;
}
現在儘管盒子的寬度稍有改變,但佈局不會打破。當然,對多列佈局來說這不一定是個好辦法,但能避免最後一列下掉。這個問題上彈性盒或許是個更好的解決方案,但這個辦法可以用來說明元素在這些環境下的行為。
總結
我希望本文已經向你展示了BFC的特性以及BFC是如何影響頁面上的元素的檢視定位的。展示其用法的例子應該有讓BFC顯得更透徹一些。
如果你有任何想要補充的,請在評論裡留言。如果你想更深入瞭解的話,一定得去回顧W3C對這個話題的詳述。
譯者註
本文中提及的浮動與行盒子變窄問題深入探討,可以參看博文:http://www.zhangxinxu.com/wordpress/?p=583
W3C標準中“除了該值被傳播到視點 viewport 的情況”,可以參看問題:http://segmentfault.com/q/1010000002645174
轉載本文亦請同時註明原出處(見本文頂部)。如您認可本文翻譯,歡迎推薦或收藏,謝謝!