塊級格式化上下文 Block formatting context (BFC)

詳情地址:塊級格式化上下文 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>

效果:

 

參考

視覺格式化模型 | MDN

塊格式化上下文| MDN

學習塊格式化上下文| 博客園

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章