前言
本文包括以下內容:
- 什么是BFC
- 如何產生BFC
- BFC的特點
- 應用BFC
1、什么是BFC
BFC (Block formatting contexts)塊級格式化上下文,首先看一下 w3c 是如何定義BFC的(大致翻譯如下):
浮動元素,絕對定位元素,非塊級盒子的塊級容器(例如 inline-blocks, table-cells, 和 table-captions),以及
overflow
不為 visiable 的塊級盒子,都會為他們的內容創建新的塊級格式化上下文。
在一個塊級格式化上下文中,盒子從頂端開始垂直地一個接一個地排列,兩個盒子之間的垂直的間隙是由他們的margin 值所決定的。在一個BFC中,兩個相鄰的塊級盒子的垂直外邊距會產生合并。
在塊級格式化上下文中,每一個盒子的左外邊緣(margin-left)會觸碰到容器的左邊緣(border-left)(對于從右到左的格式來說,則觸碰到右邊緣),即使存在浮動也是如此,除非這個盒子創建一個新的塊級格式化上下文。
可以這樣理解BFC:把BFC看作一個盒子(容器),這個BFC盒子有自己獨立的布局方式,一個BFC盒子中的元素布局不受外界影響,也不會影響到外面的元素。且在一個BFC中塊盒與行盒都會垂直排列,若存在外邊距則會產生外邊距合并。
2、如何產生BFC
在怎樣的條件下會產生塊級格式化上下文,這里引用部分 MDN關于BFC 的內容。
- 浮動元素
- 絕對定位的元素 (元素具有position為 absolute或 fixed)
- 內聯塊 inline-blocks (元素具有 display: inline-block)
- 表格單元格 、標題(元素具有 display: table-cell、table-caption,HTML表格單元格默認屬性)
- 塊元素具有
overflow
且值不是 visible的
3、BFC的特點
- 同屬一個BFC的內容會發生外邊距合并(Margin Collapse),兩個外邊距大致可以分為下列三種情況:
- 外邊距均為正值,取兩者中較大的數
- 外邊距一正一負時,取兩者相加
- 外邊距均為負時,取兩者中絕對值較大的
- BFC不會重疊浮動元素
- BFC可以包含浮動
4、應用BFC
- 解決外邊距合并的問題。
同屬一個BFC的內容會發生外邊距合并,那么,我們可以建立新的BFC,使得它們不屬于同一個BFC時則外邊距不會發生合并。
外邊距合并問題1
先是相鄰的兄弟元素外邊距合并,需要先給其中的一個盒子加上一個父元素,然后給這個父元素添加overflow:hidden
,這一點很重要,可以理解為這個屬性是為其中的content
新創建一個BFC,所以一開始在創建這個Demo的時候 我就有類似這樣的疑問:overflow:hidden 能觸發BFC,為什么不會阻止垂直外邊距疊加?
外邊距合并解決1
其實解決外邊距合并的方法其實有很多,個人覺得用BFC并不好,且麻煩,需要先創建一個父元素(因為直接給子元素.box2
設置overflow: hidden
是無效的)。當我嘗試使用另外一個方法:display: inline-block
創建BFC的時候,發現并不需要創建父元素,外邊距會直接合并。
外邊距合并解決2
這時候我就遇到了這樣一個問題: 同樣是創建BFC,為什么使用overflow: hidden
需要創建父元素,而使用display: inline-block
不需要創建父元素呢?
個人理解是這樣的:這些應用BFC的屬性,為它們的content
創建了一個新的獨立計算區域(BFC),在這塊新的獨立計算區域中與外面元素的外邊距不產生重疊,而在這塊獨立計算區域之內仍然是外邊距重疊的。
新的獨立計算區域
而當使用display: inline-block
觸發了別的外邊距合并的條件(可能是因為 IFC),并非因為BFC而發生合并。在下面的參考文章鏈接中也有指出那么一點:
inline-block元素不與任何元素的外邊距產生折疊
還可以參照下圖,可知應該是display: inline-block
的問題使得外邊距計算直接相加,當我們再使用其它屬性,如display: table-cell
的時候,仍然需要為這個元素創建父元素div.ct
然后應用屬性,產生BFC才可以生效,而直接用在相鄰元素上是無效的。
-
實現兩欄布局 及 去除文字環繞效果
當存在兩個相鄰的div
時,它們會垂直排列,但當給第一個元素設置float
屬性時,則會發生盒子重疊。假設第一個盒子比第二個盒子大(否則覆蓋后就看不到第二個盒子)。在這里會首先發現這個文字并不會被浮動元素遮擋(現在是文字較少的情況,僅4個字符),當box1
大于box2
時,這個文字仍然不會被遮擋而是跑到盒子的右側或下側(據box2
寬高決定)。
floatBox1+ box2
當文字較多時,所有的文字都會圍繞著box1
,形成文字環繞效果。而給box2
添加overflow:hidden;
時則不會再發生文字環繞。這是之前提到的BFC特性當中的一點: * BFC 不會重疊浮動元素 *,當給box2
添加屬性時,它就產生了新的BFC使得它不會再去重疊浮動的box1
同理,當去除box2
的寬度時,即可形成自適應的兩欄布局。
去除文字環繞效果 -
解決因為子元素浮動而帶來的父容器高度塌陷問題
當一個父容器中的元素都設置為浮動,且自身沒有設置高度時,則父容器的高度就會發生塌陷(就好像沒有了子元素一樣)。如下圖中的 ① 過程。而給父元素設置了overflow: hidden;
時則又發生了 ② 過程這樣的變化。這是因為這給父容器設置成了一個新的BFC,再結合之前的特性:BFC可以包含浮動 可知,就是因為這個BFC的生成使得高度不塌陷。(使用其它屬性如display: table-cell
也可使得高度不塌陷)
父容器高度塌陷
后記
使用BFC并不是很好的解決方案,像一個外邊距合并問題給人帶來的困擾就非常大,完全可以使用更簡單的方案 如給父元素添加透明的border
或padding
來解決; 像是兩欄布局以及去除文字環繞效果,也可以通過margin-left
來解決,使用overflow: hidden
也會產生新的問題,如文字溢出無法顯示;最后一個更是可以使用清除浮動(添加.clearfix
)來解決父元素高度塌陷。
這里使用BFC 僅僅是為了更好理解它而已 ~