前端知識,什麼是BFC?
什麼是BFC?
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
,left
andright
。即使有偏移,仍然保留原有的位置,其它常規流不能佔用這個位置。
浮動(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。