BFC的生成 在實現CSS的佈局時,假設我們不知道BFC的話,很多地方我們生成了BFC但是不知道.在佈局中,一個元素是block元素還是inline元素是必須要知道的.而BFC就是用來格式化塊狀元素盒子,同樣還有管理內連盒子的IFC等.那首先就來瞭解一下什麼是FC. 既然BFC是一塊獨立的渲染區域, ...
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 samples
on 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.有興趣可以研究研究.