BFC全稱是Block Formatting Context,即塊格式化上下文。它是CSS2.1規範定義的,關於CSS渲染定位的一個概念。要明白BFC究竟是什麼,首先來看看什麼是視覺格式化模型。html
視覺格式化模型(visual formatting model)是用來處理文檔並將它顯示在視覺媒體上的機制,它也是CSS中的一個概念。瀏覽器
視覺格式化模型定義了盒(Box)的生成,盒主要包括了塊盒、行內盒、匿名盒(沒有名字不能被選擇器選中的盒)以及一些實驗性的盒(將來可能添加到規範中)。盒的類型由display
屬性決定。less
塊盒有如下特性:ide
display
爲block
,list-item
或 table
時,它是塊級元素 block-level;<li>
,生成額外的盒來放置項目符號,不過多數元素只生成一個主要塊級盒。display
的計算值爲inline
,inline-block
或inline-table
時,稱它爲行內級元素;display:inline
的非替換元素生成的盒是行內盒;display
值爲 inline-block
或 inline-table
的元素生成,不能拆分紅多個盒;匿名盒也有份匿名塊盒與匿名行內盒,由於匿名盒沒有名字,不能利用選擇器來選擇它們,因此它們的全部屬性都爲inherit
或初始默認值;佈局
以下面例子,會創鍵匿名塊盒來包含毗鄰的行內級盒:flex
<div> Some inline text <p>followed by a paragraph</p> followed by more inline text. </div>
在定位的時候,瀏覽器就會根據元素的盒類型和上下文對這些元素進行定位,能夠說盒就是定位的基本單位。定位時,有三種定位方案,分別是常規流,浮動已經絕對定位。ui
position
爲static
或relative
,而且float
爲none
時會觸發常規流;position: static
,盒的位置是常規流佈局裏的位置;position: relative
,盒偏移位置由這些屬性定義top
,bottom
,left
andright
。即便有偏移,仍然保留原有的位置,其它常規流不能佔用這個位置。top
,bottom
,left
及right
;position
爲absolute
或fixed
,它是絕對定位元素;position: absolute
,元素定位將相對於最近的一個relative
、fixed
或absolute
的父元素,若是沒有則相對於body
;到這裏,已經對CSS的定位有必定的瞭解了,從上面的信息中也能夠得知,塊格式上下文是頁面CSS 視覺渲染的一部分,用於決定塊盒子的佈局及浮動相互影響範圍的一個區域。atom
float
不爲none
);position
爲absolute
或fixed
);inline-blocks
(元素的 display: inline-block
);display: table-cell
,HTML表格單元格默認屬性);overflow
的值不爲visible
的元素;display: flex
或inline-flex
);但其中,最多見的就是overflow:hidden
、float:left/right
、position:absolute
。也就是說,每次看到這些屬性的時候,就表明了該元素以及建立了一個BFC了。code
BFC的範圍在MDN中是這樣描述的。orm
A block formatting context contains everything inside of the element creating it that is not also inside a descendant element that creates a new block formatting context.
中文的意思一個BFC包含建立該上下文元素的全部子元素,但不包括建立了新BFC的子元素的內部元素。
這段看上去有點奇怪,我是這麼理解的,加入有下面代碼,class名爲.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中的元素髮生做用,就違反了BFC的隔離做用,因此這個假設就不成立了。
就如剛纔提到的,BFC的最顯著的效果就是創建一個隔離的空間,斷絕空間內外元素間相互的做用。然而,BFC還有更多的特性:
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.
In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.
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).
簡單概括一下:
這麼多性質有點難以理解,但能夠做以下推理來幫助理解:html的根元素就是<html>
,而根元素會建立一個BFC,建立一個新的BFC時就至關於在這個元素內部建立一個新的<html>
,子元素的定位就如同在一個新<html>
頁面中那樣,而這個新舊html頁面之間時不會相互影響的。
上述這個理解並非最準確的理解,甚至是將因果倒置了(由於html是根元素,所以纔會有BFC的特性,而不是BFC有html的特性),但這樣的推理能夠幫助理解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。