css 快速入門 系列 —— 浮動
浮動
以 mdn float 文檔 為基礎,逐一介紹浮動的本質、浮動的諸多特性、清除浮動以及塊格式化上下文(bfc)。
概念
當一個元素浮動之後,它會被移出正常的文檔流,然後向左或者向右平移,一直平移直到碰到了所處的容器的邊框,或者碰到另外一個浮動的元素。
卡住
如果包含塊太窄,無法容納容納水平排列的多個浮動元素,那麼其他浮動元素會向下移。如果浮動元素高度不同,就會出現」卡住「的情況:
浮動與行框盒子
如果文字很長,需要兩行顯示,而且在長文字後面跟著一個向右浮動的元素,請問該浮動元素會顯示在第一行還是第二行?
請看示例:
浮動元素會顯示在第二行。因為浮動元素會根據行框盒子進行定位,這裡有兩行,也就是兩個行框盒子,而 」more「 在第二行的行框盒子後面。
float 的本質
創建 float 或許是為了實現文字環繞圖片的效果。就像這樣:
其中圖片是左浮動 float:left;
float 從文檔流中脫離
浮動元素雖然從文檔流中脫離,但有時還是會影響不浮動的元素。
position:absolute 也會從文檔流中脫離,但不會影響不浮動的元素。我們將 文字環繞圖片 的例子用絕對定位重寫一下:
塊布局
由於 float 意味著使用塊布局,所以該浮動元素的 display 的計算值會發生變化。通常會變成 block。請看示例:
<span id="id1" style="float:left"></span>
let elem = document.getElementById('id1')
let display = window.getComputedStyle(elem).getPropertyValue('display')
// display: block
console.log('display: ', display);
所以不要再寫如下程式碼:
span {
float: left;
display: block; /* 多餘 */
}
Tip: float 元素的 display 變化值,對應關係表請看 mdn。
浮動使高度塌陷
如果一個元素里只有浮動元素,那它的高度會是 0。就像這樣:
// 核心程式碼:
<div style="border:1px solid red;">
<img style="float:left">
</div>
浮動使父元素高度塌陷,是因為浮動元素不在文檔流中。
clear
可以使用 clear 屬性來處理浮動使父元素高度塌陷的問題。
clear: none | left | right | both
字面翻譯為」清除左浮動「,或」清除右浮動「,其實這樣理解有誤。請看示例:
// 核心程式碼:
<div style="border:1px solid red;">
<img style="float:left">
Lorem ipsum, dolor
<div style="border:1px solid blue;clear:both;"></div>
</div
雖然我們使用了 clear:both,卻只解決了父元素高度塌陷問題,而浮動還是存在,因為文字仍舊環繞著圖片,故浮動沒有消除。
實際上,clear 表示框(或行框)的哪些邊(左邊或右邊)不應該挨著浮動框。對於 clear 元素,瀏覽器在該元素頂部添加足夠多的外邊距,使元素垂直下降到浮動框下面。
更通俗的說法是」左側抗浮動「、」右側抗浮動「、」兩側抗浮動「。
clear:both
clear:both 不是兩側抗浮動,準確的理解應該是左側抗浮動,或右側抗浮動。
思考這麼一個情況:如果有三個向左浮動的元素,同時在第二個元素上添加 clear:both,請問是變成兩行還是三行?
答:是 2 行。
請看示例:
為什麼會這樣?因為在 mdn float 文檔 中寫著」清除之前」的浮動,也就是說不管後端的浮動
Tip:既然只管前面的浮動,而元素要麼左浮動,要麼右浮動,所以 clear:left、clear:right 就沒什麼用了,直接寫 clear:both 就好。
clearfix
如果要讓父元素包含浮動的子元素,有一種方法叫做 clearfix,即 clear 一個不浮動的 ::after 偽元素。請看效果:
// 核心程式碼
.f-clearfix::after{display:block;content:'';clear:both;}
<div class="f-clearfix">
<img style="float:left">
</div>
Tip: clear 屬性只有塊級元素才有效。故 display 也可以設置為 table、list-item。
一側定寬的兩欄自適應布局
效果如下:
// 核心程式碼
.f-clearfix::after{display:block;content:'';clear:both;}
<!-- f-clearfix 解決父元素高度塌陷,margin-left 解決文字環繞圖片 -->
<div class="f-clearfix">
<img style="float:left;width:60px">
<div style="margin-left:70px;">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perspiciatis, nobis.</div>
</div>
注:浮動圖片與右側盒子的間距,這裡使用圖片的寬度+間隙寬度(margin-left:60px + 10px),如果只在圖片上使用 margin-right:10px,仍然會存在文字環繞圖片的問題。
margin 不會合併
浮動元素的垂直 margin 不會合併。請看示例:
// 核心程式碼
<div class='float:left;margin:10px'></div>
<div class='float:left;margin:10px'></div>
由於沒有發生合併,所以兩個盒子的垂直外邊距是 10px + 10px。
塊格式化上下文(BFC)
如果一個元素具有 bfc,那麼它的內部元素在怎麼折騰,也不會影響外部元素,而且也不會被外部元素所影響。
浮動使高度塌陷,我們有時會在父元素上設置 overflow:hidden 來解決此問題。就像這樣:
Lorem, ipsum dolor.
// 核心程式碼
<div class="overflow:hidden">
<img style="float:left">
</div>
<p>Lorem, ipsum dolor.</p>
創建 bfc 有很多方式,overflow:hidden 就是其中一種。如果不將浮動帶來的高度塌陷這個問題解決,那麼就會影響到後面元素的布局,這顯然會違背 bfc 的特性。
overflow:hidden/auto 是創建 bfc 眾多方式中為數不多的好方法。如果不考慮兼容性,display:flow-root 則是創建 fbc 最佳方式
Tip: 更多創建 bfc 的方式請看 mdn bfc。
bfc 與自適應布局
bfc 除了可以清除 float 的影響、去除 margin 重疊,還可以實現更健壯的自適應布局。
我們使用 bfc 重寫上面的「一側定寬的兩欄自適應布局」:
// 核心程式碼
<!-- `overflow:hidden;` 解決父元素高度塌陷 -->
<div class="overflow:hidden;">
<!-- `margin-right:10px` 增加與右側盒子的間距 -->
<img style="float:left;width:60px;margin-right:10px">
<!-- `overflow:hidden;` 解決文字環繞圖片 -->
<div style="overflow:hidden;">Lorem ipsum dolor sit amet consectetur adipisicing elit. Perspiciatis, nobis.</div>
</div>
Tip: 如果你的產品只需要支援 firefox 53+、chrome 58+、edge 79+,你就可以使用 display:flow-root 來創建無副作用的 bfc。並且會變成塊級元素。
