詳情地址:塊級格式化上下文 Block formatting context (BFC)
1. Box
視覺格式化模型會根據CSS盒子模型將文檔中的元素轉換爲一個個盒子。盒子主要包括了塊盒、行內盒、匿名盒(沒有名字不能被選擇器選中的盒)以及一些實驗性的盒(未來可能添加到規範中)。盒的類型由display屬性決定。
(1)塊盒
- 當元素的display爲block、list-item或table時,該元素將成爲塊級元素。
- 顯示時,豎直排列。
- 每個塊級元素都會至少生成一個塊級盒子, 稱爲主要塊級盒(principal block-level box)。一些元素,比如<li>,生成額外的盒來放置項目符號,不過多數元素只生成一個主要塊級盒。
- 每個塊級盒子都會參與塊格式化上下文(block formatting context)的創建。
- 一個塊級盒子可能也是一個塊容器盒子。塊容器盒子(block container box)要麼只包含其它塊級盒子,要麼只包含行內盒子並同時創建一個行內格式化上下文(inline formatting context)。
- 一個同時是塊容器盒子的塊級盒子稱爲塊盒子(block box )。
(2)行內盒
- 如果一個元素的display屬性爲inline、inline-block或inline-table,則稱該元素爲行內級元素。
- 顯示時,它不會生成內容塊,但是可以與其他行內級內容一起顯示爲多行。如包含多種格式內容(如強調文本、圖片等)的段落,就可以由行內級元素組成。
- 行內級元素會生成行內級盒子,該盒子同時會參與行內格式化上下文(inline formatting context)的創建。
- 行內盒子既是行內級盒子,也是一個其內容會參與創建其容器的行內格式化上下文的盒子,比如所有具有display:inline樣式的非替換盒子。
- 如果一個行內級盒子的內容不參與行內格式化上下文的創建,則稱其爲原子行內級盒子。而通過替換行內級元素或 display值爲 inline-block或 inline-table的元素創建的盒子不會像行內盒子一樣可以被拆分爲多個盒子。
(3)匿名盒
匿名盒也分匿名塊盒與匿名行內盒,因爲匿名盒沒有名字,不能利用選擇器來選擇它們,所以它們的所有屬性都爲inherit或初始默認值。
比如:
<div>
Some inline text
<p>followed by a paragraph</p>
followed by more inline text.
</div>
(4)其他
行盒子、Run-in 盒子,這裏就不介紹了
2. FC(Formatting context)
Formatting context(格式化上下文)是頁面中的一塊渲染區域,並且有一套渲染規則,它決定了其子元素將如何定位,以及和其他元素的關係和相互作用。最常見的Formatting context有Block fomatting context(BFC)和Inline formatting context(IFC)。CSS2.1 中只有BFC和IFC, CSS3中還增加了GFC和FFC。
3. BFC(Block fomatting context)
BFC是一個獨立的渲染區域,只有塊級盒子(Block-level box)參與, 它規定了內部的塊級盒子(Block-level box)如何佈局,並且與這個區域外部毫不相干。
一個BFC包含創建該上下文元素的所有子元素,但不包括創建了新BFC的子元素的內部元素。
4. BFC佈局規則
- 內部的Box會在垂直方向,一個接一個地放置;
- Box垂直方向的距離由margin決定,屬於同一個BFC的兩個相鄰Box的margin會發生重疊;
- 每個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此;
- BFC的區域不會與float box重疊;
- BFC就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面的元素。反之也如此;
- 計算BFC的高度時,浮動元素也參與計算。
5. 創建BFC的常見方法
- 根元素(<html>)
- 浮動元素(元素的float不是none)
- 絕對定位元素(元素的position爲absolute或fixed)
- 行內塊元素(元素的display爲inline-block)
- 表格單元格(元素的display爲table-cell,HTML表格單元格默認爲該值)
- overflow值不爲visible的塊元素
- 彈性元素(display爲flex或inline-flex元素的直接子元素)
- 網格元素(display爲grid或inline-grid元素的直接子元素)
其中最常見的就是overflow:hidden、float:left/right、position:absolute。每次看到這些屬性的時候,就代表了該元素創建了一個BFC。
6. BFC的作用
(1)自適應兩欄佈局
.left{
width: 200px;
height: 400px;
background-color: #A694DB;
float: left;
}
.right{
height: 600px;
background-color: #dfd8f8;
}
<div class="wrap">
<div class="left">
</div>
<div class="right">
</div>
</div>
效果如下:
顯然,上述的效果是滿足BFC佈局規則的:每個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此。
可以看到如果.left不出現浮動,那麼兩個div會垂直襬放,且它們的margin box的左邊居於包含塊(這裏是body)的border box的左邊相接觸,如果.left出現了浮動,兩個div疊在了一起,但是它們仍然滿足這一規則。
那麼,我們在實現兩欄佈局時,希望兩個div不重疊,我們可以根據BFC佈局規則:BFC的區域不會與float box重疊,來實現這一效果,我們觸發div.right生成一個BFC這樣,它就不會與浮動的div重疊,如下(只需要修改.right的樣式):
.right{
height: 600px;
background-color: #dfd8f8;
overflow: hidden;
}
效果:
(2)清除浮動
.wrap{
border: 2px solid red;
}
.p1{
width: 50px;
height: 50px;
background: #55AAFF;
float: left;
}
.p2{
float: left;
width: 50px;
height: 50px;
background: #aa55ff;
}
<div class="wrap">
<p class="p1">1</p>
<p class="p2">2</p>
</div>
我們知道,浮動的元素會脫離文檔流,這樣會造成父元素的高度塌陷問題。如下:
前面我們介紹了BFC的佈局規則,其中最後一條:計算BFC的高度時,浮動元素也參與計算。
顯然,我們利用BFC可以來解決父元素高度塌陷問題,我們可以觸發父元素div.wrap生成一個BFC,這樣計算父元素高度時,浮動元素也會參與計算,不會出現高度塌陷的問題。如下:修改div.wrap的CSS樣式即可
.wrap{
border: 2px solid red;
/* overflow: hidden; */
display: flex;
}
.p1{
width: 50px;
height: 50px;
background: #55AAFF;
float: left;
}
.p2{
float: left;
width: 50px;
height: 50px;
background: #aa55ff;
}
效果如下:
(3)防止垂直margin重疊
.p1{
width: 50px;
height: 50px;
background: #55AAFF;
margin-bottom: 20px;
}
.p2{
margin-top: 10px;
width: 50px;
height: 50px;
background: #aa55ff;
}
<body>
<p class="p1">1</p>
<p class="p2">2</p>
</body>
根據BFC佈局的第二個規則:Box垂直方向的距離由margin決定,屬於同一個BFC的兩個相鄰Box的margin會發生重疊。如下:兩個p標籤的距離是20px,發生了margin重疊
顯然,要解決這個問題,我們可以將兩個P標籤放在不同的BFC中,這樣他們的margin就不會發生重疊了。如下,我們給第一個P標籤添加一個父容器,並觸發父容器生成一個BFC,那麼這次兩個P標籤就屬於不同的BFC中了。
.wrap{
/* display: flex; */
/* overflow: hidden; */
display: inline-block;
}
.p1{
width: 50px;
height: 50px;
background: #55AAFF;
margin-bottom: 20px;
}
.p2{
margin-top: 10px;
width: 50px;
height: 50px;
background: #aa55ff;
}
<div class="wrap">
<p class="p1">1</p>
</div>
<p class="p2">2</p>
效果:
參考