什么是BFC
BFC全稱(chēng)是Block Formatting Context惦费,即塊格式化上下文舔清。它是CSS2.1規(guī)范定義的育八,關(guān)于CSS渲染定位的一個(gè)概念。要明白BFC到底是什么斯够,首先來(lái)看看什么是視覺(jué)格式化模型。
視覺(jué)格式化模型
視覺(jué)格式化模型(visual formatting model)是用來(lái)處理文檔并將它顯示在視覺(jué)媒體上的機(jī)制喧锦,它也是CSS中的一個(gè)概念读规。
視覺(jué)格式化模型定義了盒(Box)的生成,盒主要包括了塊盒燃少、行內(nèi)盒束亏、匿名盒(沒(méi)有名字不能被選擇器選中的盒)以及一些實(shí)驗(yàn)性的盒(未來(lái)可能添加到規(guī)范中)。盒的類(lèi)型由display屬性決定供汛。
塊盒(block box)
塊盒有以下特性:
當(dāng)元素的CSS屬性display為block枪汪,list-item或 table時(shí)涌穆,它是塊級(jí)元素 block-level;
視覺(jué)上呈現(xiàn)為塊雀久,豎直排列宿稀;
塊級(jí)盒參與(塊格式化上下文);
每個(gè)塊級(jí)元素至少生成一個(gè)塊級(jí)盒赖捌,稱(chēng)為主要塊級(jí)盒(principal block-level box)祝沸。一些元素,比如<li>越庇,生成額外的盒來(lái)放置項(xiàng)目符號(hào)罩锐,不過(guò)多數(shù)元素只生成一個(gè)主要塊級(jí)盒。
行內(nèi)盒(inline box)
當(dāng)元素的CSS屬性display的計(jì)算值為inline卤唉,inline-block或inline-table時(shí)涩惑,稱(chēng)它為行內(nèi)級(jí)元素;
視覺(jué)上它將內(nèi)容與其它行內(nèi)級(jí)元素排列為多行桑驱;典型的如段落內(nèi)容竭恬,有文本(可以有多種格式譬如著重),或圖片熬的,都是行內(nèi)級(jí)元素痊硕;
行內(nèi)級(jí)元素生成行內(nèi)級(jí)盒(inline-level boxes),參與行內(nèi)格式化上下文(inline formatting context)押框。同時(shí)參與生成行內(nèi)格式化上下文的行內(nèi)級(jí)盒稱(chēng)為行內(nèi)盒(inline boxes)岔绸。所有display:inline的非替換元素生成的盒是行內(nèi)盒;
不參與生成行內(nèi)格式化上下文的行內(nèi)級(jí)盒稱(chēng)為原子行內(nèi)級(jí)盒(atomic inline-level boxes)橡伞。這些盒由可替換行內(nèi)元素盒揉,或 display 值為 inline-block 或 inline-table 的元素生成,不能拆分成多個(gè)盒骑歹;
匿名盒(anonymous box)
匿名盒也有份匿名塊盒與匿名行內(nèi)盒预烙,因?yàn)槟涿袥](méi)有名字,不能利用選擇器來(lái)選擇它們道媚,所以它們的所有屬性都為inherit或初始默認(rèn)值扁掸;
如下面例子,會(huì)創(chuàng)鍵匿名塊盒來(lái)包含毗鄰的行內(nèi)級(jí)盒:
<div>
Some inline text
<p>followed by a paragraph</p>
followed by more inline text.
</div>
三個(gè)定位方案
在定位的時(shí)候最域,瀏覽器就會(huì)根據(jù)元素的盒類(lèi)型和上下文對(duì)這些元素進(jìn)行定位谴分,可以說(shuō)盒就是定位的基本單位。定位時(shí)镀脂,有三種定位方案牺蹄,分別是常規(guī)流,浮動(dòng)已經(jīng)絕對(duì)定位薄翅。
常規(guī)流(Normal flow)
- 在常規(guī)流中沙兰,盒一個(gè)接著一個(gè)排列;
- 在塊級(jí)格式化上下文里面氓奈, 它們豎著排列;
- 在行內(nèi)格式化上下文里面鼎天, 它們橫著排列;
- 當(dāng)position為static或relative舀奶,并且float為none時(shí)會(huì)觸發(fā)常規(guī)流;
- 對(duì)于靜態(tài)定位(static positioning)斋射,position: static育勺,盒的位置是常規(guī)流布局里的位置;
- 對(duì)于相對(duì)定位(relative positioning)罗岖,position: relative涧至,盒偏移位置由這些屬性定義top,bottom桑包,leftandright南蓬。即使有偏移,仍然保留原有的位置捡多,其它常規(guī)流不能占用這個(gè)位置蓖康。
浮動(dòng)(Floats)
- 盒稱(chēng)為浮動(dòng)盒(floating boxes);
- 它位于當(dāng)前行的開(kāi)頭或末尾垒手;
- 這導(dǎo)致常規(guī)流環(huán)繞在它的周邊,除非設(shè)置 clear 屬性倒信;
絕對(duì)定位(Absolute positioning)
- 絕對(duì)定位方案科贬,盒從常規(guī)流中被移除,不影響常規(guī)流的布局鳖悠;
- 它的定位相對(duì)于它的包含塊榜掌,相關(guān)CSS屬性:top,bottom乘综,left及right憎账;
- 如果元素的屬性position為absolute或fixed,它是絕對(duì)定位元素卡辰;
- 對(duì)于position: absolute胞皱,元素定位將相對(duì)于最近的一個(gè)relative、fixed或absolute的父元素九妈,如果沒(méi)有則相對(duì)于body反砌;
塊格式化上下文
到這里,已經(jīng)對(duì)CSS的定位有一定的了解了萌朱,從上面的信息中也可以得知宴树,塊格式上下文是頁(yè)面CSS 視覺(jué)渲染的一部分,用于決定塊盒子的布局及浮動(dòng)相互影響范圍的一個(gè)區(qū)域晶疼。
BFC的創(chuàng)建方法
- 根元素或其它包含它的元素酒贬;
- 浮動(dòng) (元素的float不為none)又憨;
- 絕對(duì)定位元素 (元素的position為absolute或fixed);
- 行內(nèi)塊inline-blocks(元素的 display: inline-block)锭吨;
- 表格單元格(元素的display: table-cell蠢莺,HTML表格單元格默認(rèn)屬性);
- overflow的值不為visible的元素耐齐;
- 彈性盒 flex boxes (元素的display: flex或inline-flex)浪秘;
但其中,最常見(jiàn)的就是overflow:hidden埠况、float:left/right耸携、position:absolute。也就是說(shuō)辕翰,每次看到這些屬性的時(shí)候夺衍,就代表了該元素以及創(chuàng)建了一個(gè)BFC了。
BFC的范圍
BFC的范圍在MDN中是這樣描述的喜命。
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.
中文的意思一個(gè)BFC包含創(chuàng)建該上下文元素的所有子元素沟沙,但不包括創(chuàng)建了新BFC的子元素的內(nèi)部元素。
這段看上去有點(diǎn)奇怪壁榕,我是這么理解的矛紫,加入有下面代碼,class名為.BFC代表創(chuàng)建了新的塊格式化:
<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創(chuàng)建了一個(gè)塊格式上下文颊咬,這個(gè)上下文包括了#div_2、#div_3牡辽、#div_4喳篇、#div_5。即#div_2中的子元素也屬于#div_1所創(chuàng)建的BFC态辛。但由于#div_5創(chuàng)建了新的BFC麸澜,所以#div_6和#div_7就被排除在外層的BFC之外。
我認(rèn)為奏黑,這從另一方角度說(shuō)明炊邦,一個(gè)元素不能同時(shí)存在于兩個(gè)BFC中。
BFC的一個(gè)最重要的效果是攀涵,讓處于BFC內(nèi)部的元素與外部的元素相互隔離铣耘,使內(nèi)外元素的定位不會(huì)相互影響。這是利用BFC清除浮動(dòng)所利用的特性以故,關(guān)于清除浮動(dòng)將在后面講述蜗细。
如果一個(gè)元素能夠同時(shí)處于兩個(gè)BFC中,那么就意味著這個(gè)元素能與兩個(gè)BFC中的元素發(fā)生作用,就違反了BFC的隔離作用炉媒,所以這個(gè)假設(shè)就不成立了踪区。
BFC的效果
就如剛才提到的,BFC的最顯著的效果就是建立一個(gè)隔離的空間吊骤,斷絕空間內(nèi)外元素間相互的作用缎岗。然而,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).
簡(jiǎn)單歸納一下:
內(nèi)部的盒會(huì)在垂直方向一個(gè)接一個(gè)排列(可以看作BFC中有一個(gè)的常規(guī)流)白粉;
處于同一個(gè)BFC中的元素相互影響传泊,可能會(huì)發(fā)生margin collapse;
每個(gè)元素的margin box的左邊鸭巴,與容器塊border box的左邊相接觸(對(duì)于從左往右的格式化眷细,否則相反)。即使存在浮動(dòng)也是如此鹃祖;
BFC就是頁(yè)面上的一個(gè)隔離的獨(dú)立容器溪椎,容器里面的子元素不會(huì)影響到外面的元素,反之亦然恬口;
計(jì)算BFC的高度時(shí)校读,考慮BFC所包含的所有元素,連浮動(dòng)元素也參與計(jì)算祖能;
浮動(dòng)盒區(qū)域不疊加到BFC上歉秫;
這么多性質(zhì)有點(diǎn)難以理解,但可以作如下推理來(lái)幫助理解:html的根元素就是<html>养铸,而根元素會(huì)創(chuàng)建一個(gè)BFC端考,創(chuàng)建一個(gè)新的BFC時(shí)就相當(dāng)于在這個(gè)元素內(nèi)部創(chuàng)建一個(gè)新的<html>,子元素的定位就如同在一個(gè)新<html>頁(yè)面中那樣揭厚,而這個(gè)新舊html頁(yè)面之間時(shí)不會(huì)相互影響的。
上述這個(gè)理解并不是最準(zhǔn)確的理解扶供,甚至是將因果倒置了(因?yàn)閔tml是根元素筛圆,因此才會(huì)有BFC的特性,而不是BFC有html的特性)椿浓,但這樣的推理可以幫助理解BFC這個(gè)概念太援。
從實(shí)際代碼來(lái)分析BFC
講了這么多,還是比較難理解扳碍,所以下面通過(guò)一些例子來(lái)加深對(duì)BFC的認(rèn)識(shí)提岔。
實(shí)例一
<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')向左浮動(dòng),它創(chuàng)建了一個(gè)新BFC笋敞,但暫時(shí)不討論它所創(chuàng)建的BFC碱蒙。由于綠色框浮動(dòng)了,它脫離了原本normal flow的位置,因此赛惩,粉色框('#right')就被定位到灰色父元素的左上角(特性3:元素左邊與容器左邊相接觸)哀墓,與浮動(dòng)綠色框發(fā)生了重疊。
同時(shí)喷兼,由于灰色框('#box')并沒(méi)有創(chuàng)建BFC篮绰,因此在計(jì)算高度的時(shí)候,并沒(méi)有考慮綠色框的區(qū)域(特性6:浮動(dòng)區(qū)域不疊加到BFC區(qū)域上)季惯,發(fā)生了高度坍塌吠各,這也是常見(jiàn)問(wèn)題之一。
實(shí)例二
現(xiàn)在通過(guò)設(shè)置overflow:hidden來(lái)創(chuàng)建BFC勉抓,再看看效果如何贾漏。
.BFC{
overflow: hidden;
}
<div class='box BFC'>
<div class='left'> </div>
<div class='right'> </div>
</div>
灰色框創(chuàng)建了一個(gè)新的BFC后,高度發(fā)生了變化琳状,計(jì)算高度時(shí)它將綠色框區(qū)域也考慮進(jìn)去了(特性5:計(jì)算BFC的高度時(shí)磕瓷,浮動(dòng)元素也參與計(jì)算);
而綠色框和紅色框的顯示效果仍然沒(méi)有任何變化念逞。
實(shí)例三
現(xiàn)在困食,現(xiàn)將一些小塊添加到粉色框中,看看效果:
<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>
由于粉色框沒(méi)有創(chuàng)建新的BFC翎承,因此粉色框中白色塊受到了綠色框的影響硕盹,被擠到了右邊去了。先不管這個(gè)叨咖,看看白色塊的margin瘩例。
實(shí)例四
利用同實(shí)例二中一樣的方法,為粉色框創(chuàng)建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>
一旦粉色框創(chuàng)建了新的BFC以后甸各,粉色框就不與綠色浮動(dòng)框發(fā)生重疊了垛贤,同時(shí)內(nèi)部的白色塊處于隔離的空間(特性4:BFC就是頁(yè)面上的一個(gè)隔離的獨(dú)立容器),白色塊也不會(huì)受到綠色浮動(dòng)框的擠壓趣倾。
總結(jié)
以上就是BFC的分析聘惦,BFC的概念比較抽象,但通過(guò)實(shí)例分析應(yīng)該能夠更好地理解BFC儒恋。在實(shí)際中善绎,利用BFC可以閉合浮動(dòng)(實(shí)例二),防止與浮動(dòng)元素重疊(實(shí)例四)诫尽。同時(shí)禀酱,由于BFC的隔離作用,可以利用BFC包含一個(gè)元素牧嫉,防止這個(gè)元素與BFC外的元素發(fā)生margin collapse剂跟。