BFC的生成
在實現CSS的布局時,假設我們不知道BFC的話,很多地方我們生成了BFC但是不知道.在布局中,一個元素是block元素還是inline元素是必須要知道的.而BFC就是用來格式化塊狀元素盒子,同樣還有管理內連盒子的IFC等.那首先就來了解一下什么是FC.
FC: Formatting Context指的是頁面中的一個渲染區域,並且擁有自己的渲染規則.決定子元素如何定位,以及和其他元素的相互作用和聯系.
BFC: 塊級格式化上下文, 是一個獨立的塊級渲染區域,只針對塊級元素,有一套自己的渲染規則來約束塊級盒子,與外部無關.
既然BFC是一塊獨立的渲染區域,那么這塊區域在哪里,有多大, 這就有生成BDC的元素決定,CSS2.1中規定, 滿足以下CSS聲明的元素就會生成BFC.
- 根元素
- float不為none
- overflow不為hidden
display: inline-block, table-cell, table-caption(注意: 值為table會生成BFC是因為會默認生成一個匿名的table-cell,所以不是table生成了BFC)position: absolute, fixed
BFC的約束
瀏覽器對BFC約束如下:
1. 生成BFC的子元素會一個接一個的放置,在垂直方向上的起點是包含塊的頂部,相鄰的子元素之間的垂直距離由margin控制.在BFC中相鄰的塊級元素外邊距會折疊.
2. BFC中的子元素中,每一個子元素的左外邊距與包含塊的左邊界接觸(從右到左的格式化,與右邊界接觸),即使浮動元素也如此,除非這個子元素也創建了BFC.
具體展開來說就是:
1. 內部Box在垂直方向上一個接一個放置
2. 垂直方向的距離由margin決定.
3. 每個元素的左外邊距與包含塊的左邊界接觸,即使浮動元素也是如此.所以BFC中的元素不會超出包含塊,但是position為absolute的元素可以超出包含塊的邊界.
4. BFC的區域不會與float元素的區域重合.
5. 計算BFC的高度會包含float元素,但是float元素會使父元素高度塌陷.注意區別BFC高度和父元素高度.
6. BFC相當於頁面上的一個獨立的容器.子元素不影響外部元素,反之亦然.
所以看到這些約束,一些常見的規則就可以了解原因.比如:
- 塊級元素與父元素同寬,垂直排列
- 垂直方向上的相鄰div的外邊距會折疊
- 浮動元素會盡量接近左上方
- 父元素浮動,或者overflow為hidden會包住子元素
BFC在布局中的應用
1. 解決margin折疊
同一個BFC中的兩個相鄰Box才會發生重疊與方向無關,不過由於上文提到的第一條限制,我們甚少看到水平方向的margin重疊。這在IE中是個例外,IE可以設置write-mode
<!doctype HTML><html><head><style type="text/css">#green {margin:10px 10px 10px 10px}#blue {margin:10px 10px 10px 10px}#red {margin:10px 10px 10px 10px}body {writing-mode:vertical-rl;}</style></head><body><div id="green" style="background:lightgreen;height:100px;width:100px;"></div><div id="blue" style="background:lightblue;height:100px;width:100px;"></div><div id="red" style="background:pink;height:100px;width:100px;"></div></body></html>
可以看到水平方向發生了重疊
要阻止margin重疊,只要將兩個元素別放在一個BFC中即可(可以用上文提到的方式讓相鄰元素其中一個生成BFC)。阻止兩個相鄰元素的margin重疊看起來沒有什么意義,主要用於嵌套元素。
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><!--The viewport meta tag is used to improve the presentation and behavior of the sampleson iOS devices--><meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/><title></title><style>html, body { height: 100%; width: 100%; margin: 0; padding: 0; }.first{margin:20px;background:lightgreen;width:100px;height:100px;}ul{/*display:inline-block;*/margin:10px;background:lightblue;}li{margin:25px;}</style></head><body><div class="first"></div><ul><li>1</li><li>2</li><li>3</li></ul></body></html>
此時div與ul之間的垂直距離,取div、ul、li三者之間的最大外邊距。
要阻止嵌套元素的重疊,只需讓ul生成BFC即可(將代碼中飯的display注釋去掉),這樣div、ul、li之間便不會發生重疊現象。而li位於同一BFC內所以仍然存在重疊現象。
2. 解決浮動
在清楚浮動帶來的問題的解決方案中,一定會回答用BFC清除,那到底是怎么清除的呢?根本原因就是父級元素創建BFC后,子元素即使浮動也會參與BFC高度的計算.即不會產生高度塌陷的問題.
<!DOCTYPE html><html><head><meta charset="utf-8"><title>JS Bin</title><style>html, body {height: 100%;width: 100%;margin: 0;padding: 0;}.first{margin:20px;background:lightgreen;border: 2px solid lightgreen;/*display:inline-block;*//*overflow:hidden;*//*float: left;*//*position: absolute;*/}ul{overflow:hidden;margin:10px;background:lightblue;width:100px;height:200px;float: left;}li{margin:25px;}</style></head><body><div class="first"><ul><li>1</li><li>2</li><li>3</li></ul></div></body></html>

將代碼中first樣式中任意一項注釋去掉都可以得到包圍浮動的效果,其中overflow:hidden方式,與正常流最接近。
關於清除浮動的詳細介紹,請參考這篇簡潔明了的文章.
3. 多欄布局的BFC實現
通過BFC約束: BFC的區域不會與float的元素區域重疊, 可以來實現多欄布局.
<!DOCTYPE html><html><head><meta charset="utf-8"><title>JS Bin</title><style>html, body {height: 100%;width: 100%;margin: 0;padding: 0;}.left{background:pink;float: left;width:180px;}.center{background:lightyellow;overflow:hidden;}.right{background: lightblue;width:210px;float:right;}</style></head><body><div class="container"><div class="left"><pre>.left{background:pink;float: left;width:180px;}</pre></div><div class="right"><pre>.right{background:lightblue;width:180px;float:right;}</pre></div><div class="center"><pre>.center{background:lightyellow;overflow:hidden;height:116px;}</pre></div></div></body></html>
這種布局的特點在於左右兩欄寬度固定,中間欄可以根據瀏覽器寬度自適應。
收獲
初次看到BFC這個詞,是在一個面試題上.然后百度了一下,看到了寒冬大神的一篇博客,當時看完是覺得BFC,對於大佬來說是必要的,對我而言還太早.確實,當時的我還是一個連布局什么都不是很懂的菜鳥(當然現在也是).在看了一些CSS的基礎之后,通過查閱資料,在這里提及一下,最新的布局方案Flex和Grid都會生成BFC,具體可以去看MDN,看一些前輩的心得,總是覺得會了,但是過段時間就忘掉了.俗話,能給別人講明白才是真正的理解了.所以才絞盡腦汁寫了這樣一個總結.
其實對於BFC,我們只要知道一些特定的CSS聲明會生成BFC,瀏覽器對BFC有一套特定的渲染規則,利用這些特殊的規則在布局上解決一些問題,就差不多了.但是當深入理解之后,會發現很多最常見的效果,就是因為BFC.當探究到這些的時候,前端的樂趣就在這里了.
文章中的內容可能有很問題,希望不吝指導.畢竟工作經驗對於我還是欠缺的,遇到問題探究問題的方式方法不一樣.不過話說回來,技術的樂趣就在於不斷的探究,試錯,總結積累上.
最后提一下IE,在IE中有類似的hasLayout.有興趣可以研究研究.
