BFC全稱是Block Formatting Context,即塊格式化上下文。它是CSS2.1規范定義的,關於CSS渲染定位的一個概念。要明白BFC到底是什么,首先來看看什么是視覺格式化模型。
視覺格式化模型
視覺格式化模型(visual formatting model)是用來處理文檔並將它顯示在視覺媒體上的機制,它也是CSS中的一個概念。
視覺格式化模型定義了盒(Box)的生成,盒主要包括了塊盒、行內盒、匿名盒(沒有名字不能被選擇器選中的盒)以及一些實驗性的盒(未來可能添加到規范中)。盒的類型由display屬性決定。
塊盒(block box)
- 當元素的CSS屬性
display為block,list-item或table時,它是塊級元素 block-level; - 視覺上呈現為塊,豎直排列;
- 塊級盒參與(塊格式化上下文);
- 每個塊級元素至少生成一個塊級盒,稱為主要塊級盒(principal block-level box)。一些元素,比如
<li>,生成額外的盒來放置項目符號,不過多數元素只生成一個主要塊級盒。
行內盒(inline box)
- 當元素的CSS屬性
display的計算值為inline,inline-block或inline-table時,稱它為行內級元素; - 視覺上它將內容與其它行內級元素排列為多行;典型的如段落內容,有文本(可以有多種格式譬如着重),或圖片,都是行內級元素;
- 行內級元素生成行內級盒(inline-level boxes),參與行內格式化上下文(inline formatting context)。同時參與生成行內格式化上下文的行內級盒稱為行內盒(inline boxes)。所有
display:inline的非替換元素生成的盒是行內盒; - 不參與生成行內格式化上下文的行內級盒稱為原子行內級盒(atomic inline-level boxes)。這些盒由可替換行內元素,或
display值為inline-block或inline-table的元素生成,不能拆分成多個盒;
匿名盒(anonymous box)
匿名盒也有分匿名塊盒與匿名行內盒,因為匿名盒沒有名字,不能利用選擇器來選擇它們,所以它們的所有屬性都為inherit或初始默認值;
如下面例子,會創鍵匿名塊盒來包含毗鄰的行內級盒:
<div> Some inline text <p>followed by a paragraph</p> followed by more inline text. </div>

三個定位方案
在定位的時候,瀏覽器就會根據元素的盒類型和上下文對這些元素進行定位。
盒就是定位的基本單位。定位時,有三種定位方案,分別是常規流,浮動已經絕對定位。
常規流(Normal flow)
- 在常規流中,盒一個接着一個排列;
- 在塊級格式化上下文里面, 它們豎着排列;
- 在行內格式化上下文里面, 它們橫着排列;
- 當
position為static或relative,並且float為none時會觸發常規流; - 對於靜態定位(static positioning),
position: static,盒的位置是常規流布局里的位置; - 對於相對定位(relative positioning),
position: relative,盒偏移位置由這些屬性定義top,bottom,leftandright。即使有偏移,仍然保留原有的位置,其它常規流不能占用這個位置。
浮動(Floats)
- 盒稱為浮動盒(floating boxes);
- 它位於當前行的開頭或末尾;
- 這導致常規流環繞在它的周邊,除非設置 clear 屬性;
絕對定位(Absolute positioning)
- 絕對定位方案,盒從常規流中被移除,不影響常規流的布局;
- 它的定位相對於它的包含塊,相關CSS屬性:
top,bottom,left及right; - 如果元素的屬性
position為absolute或fixed,它是絕對定位元素; - 對於
position: absolute,元素定位將相對於最近的一個relative、fixed或absolute的父元素,如果沒有則相對於body;
塊格式化上下文
到這里,已經對CSS的定位有一定的了解了,從上面的信息中也可以得知,塊格式上下文是頁面CSS 視覺渲染的一部分,用於決定塊盒子的布局及浮動相互影響范圍的一個區域。
BFC的創建方法
- 根元素或其它包含它的元素;
- 浮動 (元素的
float不為none); - 絕對定位元素 (元素的
position為absolute或fixed); - 行內塊
inline-blocks(元素的display: inline-block); - 表格單元格(元素的
display: table-cell,HTML表格單元格默認屬性); overflow的值不為visible的元素;- 彈性盒 flex boxes (元素的
display: flex或inline-flex);
但其中,最常見的就是overflow:hidden、float:left/right、position:absolute。也就是說,每次看到這些屬性的時候,就代表了該元素以及創建了一個BFC了。
BFC的范圍
先看一段代碼
<div id='div_1' class='BFC'>
<div id='div_2'>
<div id='div_3'></div>
<div id='div_4'></div>
</div>
<div id='div_5' class='BFC'>
<div id='div_6'></div>
<div id='div_7'></div>
</div>
</div>
這段代碼表示,#div_1創建了一個塊格式上下文,這個上下文包括了#div_2、#div_3、#div_4、#div_5。即#div_2中的子元素也屬於#div_1所創建的BFC。但由於#div_5創建了新的BFC,所以#div_6和#div_7就被排除在外層的BFC之外。
這從另一方角度說明,一個元素不能同時存在於兩個BFC中。
BFC的效果
就如剛才提到的,BFC的最顯著的效果就是建立一個隔離的空間,斷絕空間內外元素間相互的作用。然而,BFC還有更多的特性。
簡單歸納一下:
- 內部的盒會在垂直方向一個接一個排列(可以看作BFC中有一個的常規流);
- 處於同一個BFC中的元素相互影響,可能會發生margin collapse;
- 每個元素的margin box的左邊,與容器塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此;
- BFC就是頁面上的一個隔離的獨立容器,容器里面的子元素不會影響到外面的元素,反之亦然;
- 計算BFC的高度時,考慮BFC所包含的所有元素,連浮動元素也參與計算;
- 浮動盒區域不疊加到BFC上;
這么多性質有點難以理解,但可以作如下推理來幫助理解:html的根元素就是<html>,而根元素會創建一個BFC,創建一個新的BFC時就相當於在這個元素內部創建一個新的<html>,子元素的定位就如同在一個新<html>頁面中那樣,而這個新舊html頁面之間時不會相互影響的。
上述這個理解並不是最准確的理解,甚至是將因果倒置了(因為html是根元素,因此才會有BFC的特性,而不是BFC有html的特性),但這樣的推理可以幫助理解BFC這個概念。
從實際代碼來分析BFC
以上花里胡哨一頓說,比較難理解,下面通過一些例子來加深對BFC的認識吧~
實例一
<style>
* {
margin: 0;
padding: 0;
}
.left{
background: #73DE80; /* 綠色 */
opacity: 0.5;
border: 3px solid #F31264;
width: 200px;
height: 200px;
float: left;
}
.right{ /* 粉色 */
background: #EF5BE2;
opacity: 0.5;
border: 3px solid #F31264;
width:400px;
min-height: 100px;
}
.box{
background:#888;
height: 100%;
margin-left: 50px;
}
</style>
<div class='box'>
<div class='left'> </div>
<div class='right'> </div>
</div>
顯示效果如下

綠色框('#left')向左浮動,它創建了一個新BFC,但暫時不討論它所創建的BFC。由於綠色框浮動了,它脫離了原本normal flow的位置,因此,粉色框('#right')就被定位到灰色父元素的左上角(特性3:元素左邊與容器左邊相接觸),與浮動綠色框發生了重疊。
同時,由於灰色框('#box')並沒有創建BFC,因此在計算高度的時候,並沒有考慮綠色框的區域(特性6:浮動區域不疊加到BFC區域上),發生了高度坍塌,這也是常見問題之一。
實例二
現在通過設置overflow:hidden來創建BFC,再看看效果如何。
.BFC{
overflow: hidden;
}
<div class='box BFC'>
<div class='left'> </div>
<div class='right'> </div>
</div>

灰色框創建了一個新的BFC后,高度發生了變化,計算高度時它將綠色框區域也考慮進去了(特性5:計算BFC的高度時,浮動元素也參與計算);
綠色框和紅色框的顯示效果仍然沒有任何變化。
實例三
<style> .little{ background: #fff; width: 50px; height: 50px; margin: 10px; float: left; } </style> <div class='box BFC'> <div class='left'> </div> <div class='right'> <div class='little'></div> <div class='little'></div> <div class='little'></div> </div> </div>

由於粉色框沒有創建新的BFC,因此粉色框中白色塊受到了綠色框的影響,被擠到了右邊去了。先不管這個,看看白色塊的margin。
實例四
利用同實例二中一樣的方法,為粉色框創建BFC:
<div class='box BFC'>
<div class='left'> </div>
<div class='right BFC'>
<div class='little'></div>
<div class='little'></div>
<div class='little'></div>
</div>
</div>

一旦粉色框創建了新的BFC以后,粉色框就不與綠色浮動框發生重疊了,同時內部的白色塊處於隔離的空間(特性4:BFC就是頁面上的一個隔離的獨立容器),白色塊也不會受到綠色浮動框的擠壓。
總結
以上就是BFC的分析,BFC的概念比較抽象,但通過實例分析應該能夠更好地理解BFC。
在實際中,利用BFC可以閉合浮動(實例二),防止與浮動元素重疊(實例四)。
同時,由於BFC的隔離作用,可以利用BFC包含一個元素,防止這個元素與BFC外的元素發生margin collapse。
