《洛谷CF375D Tree and Queries》
float屬性,會使元素向左或向右移動,其周圍的元素也會重新排列。float不僅自己飄忽不定,還對周圍元素有影響,這種影響力不容小覷。他捉摸不定(浮動規律不好把握),他干涉他國內政(對周圍元素有影響),這些特點就像今天的美國總統特朗普(別名“特不靠譜”)。學習float就得了解它的前世今生,它的本質,掌握它的規律才能降妖除魔,為我所用。
一、float的前世今生
float設計之初,目的就是圖文環繞
如果float一直踏踏實實、本本分分的幹好本職工作,那他就是一個“好人”。float本該“不忘初心,牢記使命”,就像我們黨開展的教育活動那樣,可是他後來忘記了自己的初衷,竟參與到網頁佈局中,一度還樂此不疲,甚至受到一些程式設計師青睞。
最早的網頁佈局很簡單,元素的排列就是靠table、tr、td這樣一些標籤,頁面很簡單,float就是用來做圖文環繞的,但是後來程式設計師發現float用在佈局上也不錯,打破了tabel(tr、td)標籤死板的佈局方式,float佈局更加靈活多樣。這樣float就開始了“華麗轉身”,正式成為網頁佈局中的一員大將。
其實,float有很多毛病,他的浮動規律讓很多人摸不著頭腦,而且周圍元素經常受到影響,稍有不慎原有的排佈會支離破碎,所以有人說他是“魔鬼”,說他是“混球”,說他是“不務正業”,說他“跨界太大”,一點也不為過。
隨著瀏覽器版本的升級,float在佈局方面的作用逐漸被取代,但是,由於float的相容性好,儘管他有很多問題,人們還是(不得不)包容他,在研究浮動規律的基礎上,駕馭他、降伏他、利用他。
二、float的浮動規律
(一)float的本質
1、包裹性(與inline-block\block對比)
包裹性就是在未設定寬度的情況下,根據內容自適應(也可以叫“自收縮”)。如下圖:
具有包裹性的還有display:inline-block、position:absolute、position:fixed等。
在佈局上float與inline-block很相似,如下圖:
雖然很相似,但是仔細觀察上圖還是有些差別,比如li之間的縫隙,inline-block中間有縫,float中間沒縫,在實際佈局中,一般都希望中間沒縫,這樣便於計算尺寸。所以,float在這方面有先天優勢(float能去空格,嚴絲合縫適合網頁佈局,通常把float佈局叫做“碼磚頭”)。當然,如果你不介意中間的縫隙,或者採用一些辦法去掉縫隙,也可以採用inline-block,實際情況下,如果程式碼稍微複雜些,inline-block可能還會出現垂直對齊(vertical-align)的問題,到時你可以查閱一些資料來解決問題。
不要以為float和inline-block比較相似,就以為浮動元素的顯示方式(display)就是inline-block,實際上,浮動元素的顯示方式(display)是block,確切地說是“通常情況下,浮動元素display:block”,有些情況雖然不是block,比如display:list-item,本質上也和block差不多。
下圖,span元素本來是內聯元素(display:inline)浮動(float:left)後,我們通過瀏覽器右鍵的“審查元素”可以看到display:block
這樣,行內元素(比如span標籤、a標籤)和塊元素(比如div標籤)一旦浮動後都是一樣的效果了,就是說<div style=”float:left;background:#ccc”>浮動元素</div>與<span style=”float:left;background:#ccc”>浮動元素</span>是完全一樣的。這時再加上display屬性就多餘了,加上display屬性(比如display:inline)瀏覽器也不會採用,純屬畫蛇添足。
有人就問了“多個浮動元素可以水平排列在同一行,而浮動元素display:block就應該獨佔一行呀!,這不是互相矛盾嗎?”,你看到上圖中的那個詞語了嗎?“特殊”的塊元素。因為浮動元素脫離了文件流(標準流),此時的塊元素(display:block)已不是標準流中的塊元素了,它自收縮(包裹性),不再佔用整行寬度,所以多個浮動元素可以水平排列在同一行。
補充一點,浮動元素“脫離標準流”,這裡的“脫離標準流”和position:absolute脫離標準流不太一樣,float的脫離標準流,在自由度上受限,不是自由翱翔的那種,而absolute脫離標準流是可以滿世界亂跑的那種,自由度很大。所以,有的資料中不認可“浮動元素脫離標準流”的說法。本文不過於追究細節,籠統地說“浮動元素脫離標準流”,讀者可以粗略這麼理解。
2、破壞性
破壞性,就是打破規則,並且影響周圍元素。就像特朗普不斷退群,不斷修改規則,儘管讓別的國家不知所措,對美國心生怨恨,但礙於美國實力,只能忍氣吞聲。
本文第一張圖的第一部分,圖片浮動前和文字基線對齊,在一行顯示,圖片高度比文字高,所以圖片所在的這行跟別的(純文字)行就不一樣,這行顯得很高,其實就是圖片給撐起來的。
圖片浮動(float:left)後,以往的規則打破了,它像一副軀殼一樣向左移動,它和文字不再基線對齊,打破了原有的規則。破壞性不僅表現在對齊方式的改變,還表現在父元素的高度塌陷上(子元素在浮動前要向父元素彙報高度,父元素把所有子元素的高度收集到後就確定了自己的高度,子元素浮動後,就不再向父元素彙報高度了,因此父元素收集不到子元素的高度就導致自己的高度塌陷)。
(二)浮動規則
1、圖文環繞可以推廣為:行內級內容會被浮動元素推出去(行內級內容包括行內級元素、inline-block元素、塊級元素的文字內容)
行內級內容被浮動元素推出
提示讀者,操作時注意調整瀏覽器的寬度
2、浮動元素只能在當前行中移動(float:left,從右向左移動 float:right相反),遇到包含塊(父元素)或其他浮動元素的邊界為止。如果水平方向剩餘的空間不夠顯示,浮動元素將向下移動,直到有足夠的空間位置為止。
下面的程式碼
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
7 <title>code2</title>
8 </head>
9
10 <body>
11 這是第一部分文字,如果瀏覽器的寬度較小,這段文字會在圖片的上方
12 <img src="img/pic1.jpg" style="float:left;">
13 <span style="color:#000;">第二部分文字,其他內容,其他內容,其他內容,其他內容(更多內容在此省略)</span>
14 </body>
15 </html>
View Code
在瀏覽器寬度較大時,第一部分文字和第二部分文字都在圖片右側排列
在瀏覽器寬度較小時,第一部分文字在圖片的上方排列
下面的程式碼是幾個div浮動後排布的情況
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
7 <title>test</title>
8 </head>
9 <style>
10 .box1{width:200px;height:400px;background:blue;}
11 .box2{width:300px;height:300px;background:yellow;}
12 .box3{width:400px;height:200px;background:purple;}
13 .box4{width:100px;height:500px;background:red;}
14 .box5{width:500px;height:400px;background:green;}
15 .box6{width:500px;height:100px;background:gray;}
16 .box7{width:100px;height:400px;background:orange;}
17 .box8{width:400px;height:400px;background:#ccc;}
18 div{float:left;}
19 </style>
20 <body>
21 <div class="box1">box1</div>
22 <div class="box2">box2</div>
23 <div class="box3">box3</div>
24 <div class="box4">box4</div>
25 <div class="box5">box5</div>
26 <div class="box6">box6</div>
27 <div class="box7">box7</div>
28 <div class="box8">box8</div>
29
30 </body>
31 </html>
View Code
程式碼結構:八個div都是float:left,box1至box8依次,儘管瀏覽器寬度不同時,浮動元素排布的結果不同,但是都遵循一定的規則,請看下圖
為了說明問題,稍微刪減部分div,div仍然都是float:left,div的寬、高有所調整
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
7 <title>code4</title>
8 </head>
9 <style>
10 .box1{width:400px;height:100px;background:blue;}
11 .box2{width:100px;height:500px;background:yellow;}
12 .box3{width:300px;height:200px;background:purple;}
13 .box4{width:300px;height:300px;background:red;}
14 .box5{width:300px;height:300px;background:green;}
15 div{float:left;}
16 </style>
17 <body>
18 <div class="box1">box1</div>
19 <div class="box2">box2</div>
20 <div class="box3">box3</div>
21 <div class="box4">box4</div>
22 <div class="box5">box5</div>
23
24 </body>
25 </html>
View Code
由以上圖可見,浮動元素的排列有相當嚴格的等級制度,後浮動的元素只能與前面的浮動元素在同一水平線上(以頂部為準),前提是後面的空間足夠大。如果後面的空間不夠,就會向下錯位,錯位後如果沒有遇到阻力,還是水平移動(float:left從右向左移動,float:right相反),移動過程中不會再上移動,水平移動直到遇到阻力,永遠不會出現後面的浮動元素高於前面的浮動元素(以頂部為準)。就是說,後浮動的元素要麼與前面的浮動元素平起平坐(頂部在同一水平線上),前提是後面的空間足夠大;如果後面的空間不夠,後浮動的元素只能處於下層,永遠不會出現“僭越”,等級森嚴!
三、清除浮動
float是魔鬼,是混球,是黑惡勢力,清除浮動就是“降妖除魔”,就是“掃黑除惡”。
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <meta http-equiv="X-UA-Compatible" content="ie=edge">
7 <title>code5</title>
8 </head>
9 <style>
10 .wrap{background:red;}
11 .wrap:after{display:block;content:'';clear:both;}
12 .content{float:left;width:300px;height:100px;}
13 .content1{background:lightblue;}
14 .content2{background:lightgreen;}
15 .content3{background:darkblue;}
16
17
18 .footer{height:50px;background:#ccc;}
19 </style>
20 <body>
21 <div class="wrap">
22 <div class="content content1"></div>
23 <div class="content content2"></div>
24 <div class="content content3"></div>
25 </div>
26 <div class="footer">footer</div>
27 </body>
28 </html>
View Code
方法1、增加一個額外的div(clear:both)
<div class="wrap">
<div class="content content1"></div>
<div class="content content2"></div>
<div class="content content3"></div>
<div style=”clear:both;”></div>
</div>
<div class="footer">footer</div>
這種方法就是相當於加了一個防火牆(防魔牆),打了一個隔板,但是因為增加了額外標籤,可讀性不強,所以不怎麼推薦。
方法2、在父元素(class=”wrap”)填加屬性overflow:hidden
.wrap{overflow:hidden;}
這種方法的解釋,很難用一句話兩句哈說清楚,所以本文不解釋理由,這種方法相容性也還可以,所以推薦使用。
方法3、使用父元素的偽類選擇器
.wrap:after{display:block;content:””;clear:both;}
這跟方法1的道理差不多,但是沒有增加額外標籤,相容性也還可以,所以推薦使用。
四、float的未來命運
我們使用float浮動做了很多其本職工作以外的事情。目前用float實現的不管是分欄佈局,還是列表排列,我們都可以用其他一些CSS屬性代替實現,唯一一個實現不了的就是“文字環繞圖片”。未來,float可能會再回到老本行,只做圖文環繞,把網頁佈局交給其他屬性,也就是說float可能會退出網頁佈局的歷史舞臺。但那是將來的事,如果你對瀏覽器的相容性有較高要求,你還不得不掌握它的浮動規律。
雖然很相似,但是仔細觀察上圖還是有些差別,比如li之間的縫隙,inline-block中間有縫,float中間沒縫,在實際佈局中,一般都希望中間沒縫,這樣便於計算尺寸。所以,float在這方面有先天優勢(float能去空格,嚴絲合縫適合網頁佈局,通常把float佈局叫做“碼磚頭”)。當然,如果你不介意中間的縫隙,或者採用一些辦法去掉縫隙,也可以採用inline-block,實際情況下,如果程式碼稍微複雜些,inline-block可能還會出現垂直對齊(vertical-align)的問題,到時你可以查閱一些資料來解決問題。
不要以為float和inline-block比較相似,就以為浮動元素的顯示方式(display)就是inline-block,實際上,浮動元素的顯示方式(display)是block,確切地說是“通常情況下,浮動元素display:block”,有些情況雖然不是block,比如display:list-item,本質上也和block差不多。
下圖,span元素本來是內聯元素(display:inline)浮動(float:left)後,我們通過瀏覽器右鍵的“審查元素”可以看到display:block