什么是BFC?
前言
對(duì)于BFC的概念以及應(yīng)用場(chǎng)景一直都不是很明白,今天著重去了解了一下,做了以下總結(jié)。
BFC的定義
在解釋 BFC 是什么之前,需要先介紹 Box、Formatting Context的概念。
Box: CSS布局的基本單位
??Box 是 CSS 布局的對(duì)象和基本單位, 直觀點(diǎn)來說,就是一個(gè)頁(yè)面是由很多個(gè) Box 組成的。元素的類型和 display 屬性,決定了這個(gè) Box 的類型。 不同類型的 Box, 會(huì)參與不同的 Formatting Context(一個(gè)決定如何渲染文檔的容器),因此Box內(nèi)的元素會(huì)以不同的方式渲染。讓我們看看有哪些盒子: block-level box:display 屬性為 block, list-item, table 的元素,會(huì)生成 block-level box。并且參與 block fomatting context; inline-level box:display 屬性為 inline, inline-block, inline-table 的元素,會(huì)生成 inline-level box。并且參與 inline formatting context; run-in box: css3 中才有, 這兒先不講了。
Formatting context
??Formatting context 是 W3C CSS2.1 規(guī)范中的一個(gè)概念。它是頁(yè)面中的一塊渲染區(qū)域,并且有一套渲染規(guī)則,它決定了其子元素將如何定位,以及和其他元素的關(guān)系和相互作用。最常見的 Formatting context 有 Block fomatting context (簡(jiǎn)稱BFC)和 Inline formatting context (簡(jiǎn)稱IFC)。 CSS2.1 中只有 BFC 和 IFC, CSS3 中還增加了 GFC 和 FFC。
BFC
? BFC(Block Formatting Context)直譯為“塊級(jí)格式化范圍”。是 W3C CSS 2.1 規(guī)范中的一個(gè)概念,它決定了元素如何對(duì)其內(nèi)容進(jìn)行定位,以及與其他元素的關(guān)系和相互作用 當(dāng)涉及到可視化布局的時(shí)候,Block Formatting Context提供了一個(gè)環(huán)境,HTML元素在這個(gè)環(huán)境中按照一定規(guī)則進(jìn)行布局。一個(gè)環(huán)境中的元素不會(huì)影響到其它環(huán)境中的布局。比如浮動(dòng)元素會(huì)形成BFC,浮動(dòng)元素內(nèi)部子元素的主要受該浮動(dòng)元素影響,兩個(gè)浮動(dòng)元素之間是互不影響的。這里有點(diǎn)類似一個(gè)BFC就是一個(gè)獨(dú)立的行政單位的意思。 也可以說BFC就是一個(gè)作用范圍。可以把它理解成是一個(gè)獨(dú)立的容器,并且這個(gè)容器的里box的布局,與這個(gè)容器外的毫不相干
怎樣才能形成BFC
float的值不能為none
overflow的值不能為visible
display的值為table-cell, table-caption, inline-block中的任何一個(gè)
position的值不為relative和static
BFC的約束規(guī)則
內(nèi)部的Box會(huì)在垂直方向上一個(gè)接一個(gè)的放置
垂直方向的距離有margin決定(屬于同一個(gè)BFC的兩個(gè)相鄰Box的margin會(huì)發(fā)生重疊,與方向無關(guān))
每個(gè)元素的margin box的左邊, 與包含塊border box的左邊相接觸(對(duì)于從左往右的格式化,否則相反)。即使存在浮動(dòng)也是如此
BFC的區(qū)域不會(huì)與float的元素區(qū)域重疊
計(jì)算BFC的高度時(shí),浮動(dòng)子元素也參與計(jì)算
BFC就是頁(yè)面上的一個(gè)隔離的獨(dú)立容器,容器里面的子元素不會(huì)影響到外面元素,反之亦然
看到以上的幾條約束,讓我想起學(xué)習(xí)css時(shí)的幾條規(guī)則
Block元素會(huì)擴(kuò)展到與父元素同寬,所以block元素會(huì)垂直排列 垂直方向上的兩個(gè)相鄰DIV的margin會(huì)重疊,而水平方向不會(huì)(此規(guī)則并不完全正確) 浮動(dòng)元素會(huì)盡量接近往左上方(或右上方) 為父元素設(shè)置overflow:hidden或浮動(dòng)父元素,則會(huì)包含浮動(dòng)元素
BFC的作用
1. 不和浮動(dòng)元素重疊
如果一個(gè)浮動(dòng)元素后面跟著一個(gè)非浮動(dòng)的元素,那么就會(huì)產(chǎn)生一個(gè)覆蓋的現(xiàn)象,很多自適應(yīng)的兩欄布局就是這么做的。比如下圖的效果,參考例子
? ? body {? ? ? ? width: 300px;? ? ? ? position: relative;? ? }? ? .aside {? ? ? ? width: 100px;? ? ? ? height: 150px;float: left;? ? ? ? background:#f66;}? ? .main {? ? ? ? height: 200px;? ? ? ? background:#fcc;}? ?
? ?

案例分析: 很明顯,.aside和.mian重疊了。試分析一下,由于兩個(gè)box都處在同一個(gè)BFC中,都是以BFC邊界為起點(diǎn),如果兩個(gè)box本身都具備BFC的話,會(huì)按順序一個(gè)一個(gè)排列布局,現(xiàn)在.main并不具備BFC,根據(jù)BFC布局規(guī)則第3條
每個(gè)元素的margin box的左邊, 與包含塊border box的左邊相接觸(對(duì)于從左往右的格式化,否則相反)。即使存在浮動(dòng)也是如此。
雖然存在浮動(dòng)的元素aslide,但main的左邊依然會(huì)與包含塊的左邊相接觸 根據(jù)BFC布局規(guī)則第四條:
BFC的區(qū)域不會(huì)與float box重疊
我們可以通過通過觸發(fā)main生成BFC, 來實(shí)現(xiàn)自適應(yīng)兩欄布局
.main {
? ? overflow: hidden;
}
當(dāng)觸發(fā)main生成BFC后,這個(gè)新的BFC不會(huì)與浮動(dòng)的aside重疊。因此會(huì)根據(jù)包含塊的寬度,和aside的寬度,自動(dòng)變窄。效果如下:

2. 清除元素內(nèi)部浮動(dòng)
案例代碼:
? ? .par {? ? ? ? border: 5px solid#fcc;width: 300px;? ? }? ? .child {? ? ? ? border: 5px solid#f66;width:100px;? ? ? ? height: 100px;float: left;? ? }? ?

根據(jù)BFC布局規(guī)則第六條:
計(jì)算BFC的高度時(shí),浮動(dòng)元素也參與計(jì)算
為達(dá)到清除內(nèi)部浮動(dòng),我們可以觸發(fā)par生成BFC,那么par在計(jì)算高度時(shí),par內(nèi)部的浮動(dòng)元素child也會(huì)參與計(jì)算。
.par{
? overflow:hidden
}
加入上面樣式,即可解決問題,效果如下:

3. 防止垂直 margin 重疊
? ? p {? ? ? ? color:#f55;background:#fcc;width: 200px;? ? ? ? line-height: 100px;? ? ? ? text-align:center;? ? ? ? margin: 100px;? ? }? ?

頁(yè)面如下:

兩個(gè)p之間的距離為100px,發(fā)送了margin重疊。根據(jù)BFC布局規(guī)則第二條:
Box垂直方向的距離由margin決定。屬于同一個(gè)BFC的兩個(gè)相鄰Box的margin會(huì)發(fā)生重疊
我們可以在p外面包裹一層容器,并觸發(fā)該容器生成一個(gè)BFC。那么兩個(gè)P便不屬于同一個(gè)BFC,就不會(huì)發(fā)生margin重疊了。
? ? .wrap {? ? ? ? overflow: hidden;? ? }? ? p {? ? ? ? color:#f55;background:#fcc;width: 200px;? ? ? ? line-height: 100px;? ? ? ? text-align:center;? ? ? ? margin: 100px;? ? }??

效果如下:

按照BFC的定義,只有同屬于一個(gè)BFC時(shí),兩個(gè)元素才有可能發(fā)生垂直Margin的重疊,這個(gè)包括相鄰元素,嵌套元素,只要他們之間沒有阻擋(例如邊框,非空內(nèi)容,padding等)就會(huì)發(fā)生margin重疊。 因此要解決margin重疊問題,只要讓它們不在同一個(gè)BFC就行了,但是對(duì)于兩個(gè)相鄰元素來說,意義不大,沒有必要給它們加個(gè)外殼,但是對(duì)于嵌套元素來說就很有必要了,只要把父元素設(shè)為BFC就可以了。這樣子元素的margin就不會(huì)和父元素的margin發(fā)生重疊了。