1. 程式人生 > >CSS進階(9)—— 那些年騙過你的float和“清浮動”

CSS進階(9)—— 那些年騙過你的float和“清浮動”

  如果你被這個標題騙進來,那恭喜你,你獲得了一個重新認識float的機會,這句話不僅是我想對前端程式猿說的,也是我想對自己說的。在使用flex佈局之前,float一度是我最最喜歡用的佈局方式,在沒有接觸CSS world之前,我甚至認為float才是最符合"流"特質的屬性,我自己將float屬性定義成CSS的“果凍屬性”,可能是因為float元素會像一顆果凍一樣在圖文間滑來滑去。事實上,我們都知道,float是一種破壞文件流的屬性,除了float,position屬性不為static/relative的時候也會破壞文件流,但他們破壞的方式卻差很多,相比之下,float要溫和的多,因為float還要顧慮相鄰節點的感受,在遇到圖文的時候,float會選擇繞道而行,而position:absolute/fixed則不同,他們只管最近的具有定位屬性的父節點。因此,float的破壞方式較為溫和,像個果凍,而position的破壞方式比較暴力,像一片雲,超脫於一切之上,完全飄了的感覺。

  說了這麼多,有些跑題,下面正式開始本章的內容,深入瞭解float,在過程中揭祕我們對浮動以及清浮動深深的“誤解”。

1.探究圖片環繞文字的傳說

  在深入瞭解float之前,相信大家都聽過一個傳說,就是float被設計出來的目的是為了實現文字環繞圖片的效果,可能是初學的時候忘了,還是受了“清浮動”的毒,我自己都忘了有沒有用float去實現過這個效果。因此下面我們先來實現一下float的設計初衷,文字環繞圖片效果。

<div style="width: 200px">
	<div style="float: left;">
		<img width="100" height="100" src="../小和尚.jpg">
	</div>
	<p>我想實現文字環繞,因此需要多一些文字看一下效果我想實現文字環繞,因此需要多一些文字看一下效果</p>
</div>

  非常簡單的一段程式碼,也不需要什麼牛逼哄哄的操作,float就幫助我們實現了文字環繞圖片的效果。為了實現這種效果,CSS設計師在設計float屬性的時候定義了float的兩個特性。

  (1)“破壞文件流”,使得父元素得高度塌陷。

  (2)禁止行框盒子與浮動元素髮生重疊。

  下面我們結合這兩個特性,來說說圖片是如何環繞文字的。第一點,破壞文件流,使得父元素高度塌陷,這個時候,我們的p標籤作為一個block元素,肯定是想著我要填滿父容器的寬度,而事實上,塊級元素也是不辱使命的完成了自己的任務,我們可以給塊級標籤加個背景色,然後把圖片搞成小透明,看一下是不是這樣。

  果然,第一個條件生效了,然而高度塌陷只是讓浮動元素和塊級元素在一個水平線上了,如何實現文字環繞效果呢?這個時候就需要我們的第二個屬性出場了,就是float元素禁止與行框盒子發生重疊(個人認為這是float和絕對定位的最大區別之一),對“行框盒子”還不理解的童鞋請轉內聯元素那章。注意,我特意強調了行框盒子,也就是本例中匿名內聯元素生成的每一行,這個跟塊級元素的盒子沒有半毛錢關係。為了驗證這個想法,我們可以把p標籤轉化成內聯元素(display:inline)看下效果。為了看上去更明顯,我把圖片的透明度設成了0,可以看到,浮動元素確實是和行框盒子發生了不重疊的關係。

  至此,我們已經完全瞭解了那個float的傳說。

2.浮動錨點和浮動參考?聽都沒聽過!

  我估計在座的各位和我一樣(是個辣雞),都是第一次聽說浮動錨點和浮動參考,更別說去了解特麼的概念了。乾巴巴的講概念在CSS世界裡根本行不通,很多東西都要通過實踐,確認過眼神才能夠去猜測其內部的原理。那麼我們就通過一個例子來了解一下這兩個概念。

<!-- 測試浮動參考 -->
<div style="width: 200px;text-align: justify;background: yellow">
	<span>這裡有很多文字,且要超出一行且要超出一行且要超出一行</span>
	<span style="float: right;color:blue">更多</span>
</div>

  首先上面這個例子,文字超出一行的時候,浮動元素會浮在哪兒?是文字的第一行?還是文字的最後一行?還是隨便浮?答案是,最後一行,看一下具體效果就知道了。

  既然結果已經出來了,那麼,為什麼呢?

  這個時候就要邀請我們的浮動參考出場了。浮動參考,顧名思義,就是指float元素要對齊參考的實體是誰?

  在CSS世界中,float元素的浮動參考是“行框盒子”,這個行框盒子特麼又出來了,怎麼感覺哪兒都有它。注意是行框盒子,跟其父容器子元素等等等等都沒半毛錢關係。這裡作者溫馨提示,在新的標準中,float的浮動參考不僅僅是行框盒子,但他沒有展開,我也懶得查閱,就當留個懸念。知道了浮動參考的概念後,我們就可以解釋上面這個例子了,由於float元素是參考行框盒子對齊的,因此,float可能在第一行,也可能在第二行,為什麼在第三行呢?

  這裡其實作者沒有說明,我提出一個假設就是浮動元素參考的是離他最近的行框盒子,這個觀點由本人提出,由本人驗證後發現事實就是這樣,所以有時候CSS的世界就是瞎猜一通然後驗證。下面我來簡單驗證一下這個觀點,其實很簡單,只要把浮動元素放到span標籤前面就可以了。如下所示

<!-- 驗證浮動參考是離他最近的行框盒子 -->
<div style="width: 200px;text-align: justify;background: yellow">
	<span style="float: right;color:blue">更多</span>
	<span>這裡有很多文字,且要超出一行且要超出一行且要超出一行</span>
</div>

  結果完全印證了我的想法是正確的,我吹爆我自己!

  說完了浮動參考,那麼什麼是浮動錨點?浮動錨點是float元素所在流中的一個點,你可以理解為是一個空的內聯元素,為什麼要有這個點呢?道理很簡單,有時候我們的浮動元素沒有可以參考的行框盒子,也就是他的四周都被一群block大漢包圍的時候該怎麼辦?往哪裡定位?沒有關係,他自己帶一個可以參考的浮動錨點。由於這個屬性沒什麼特殊之處,這裡就不過多介紹了,瞭解一下就好。

3.那些年你被騙過的clear“清浮動”

  相信我們初學浮動的第一課便被灌輸了“浮動”破壞文件流是個禍害的思想,為了解決浮動元素導致高度坍塌的“bug”,我們被要求清浮動。然後給了一大堆清浮動的方法,最後提出最好用的是after偽類清浮動,當時還真覺得煞有其是,現在看來真的是人言可畏。如果CSS自家制定的標準都被當作了bug,那還有什麼不是bug呢?

  看完這一章後,你應該可以明白兩個概念,第一,浮動引起的高度坍塌是為了解決圖文環繞效果而被制定的標準,並不是所謂的bug。第二,所謂的clear清浮動,並沒有清除掉浮動

  為什麼說clear沒有清除掉浮動呢?從字面意思上理解,clear確實是清除的意思,然而官方對於clear的解釋是:

  元素盒子的邊不能和前面的浮動元素相鄰。

  這句話聽起來很拗口,但可以明確的知道,clear並沒有改變任何浮動元素的特性,浮動元素依舊是那個浮動元素,不管你清不清,他還是在那邊,浮著。

  那麼這句話的涵義是什麼呢?仔細剖析一下,你會發現,“清浮動”的奧祕就在於這個不能相鄰的標準。事實上,clear被制定出來就是為了解決口耳相傳的“高度坍塌bug”,因此浮動元素本身的特性被完美保留。概念講的幹了,來看一個例子吧

<!-- 清浮動原理探究 -->
<div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
</div>
<style>
	.li{
		float: left;
		margin: 10px;
		width: 40px;
		height: 40px;
		background: yellow
	}
	.li:nth-of-type(3){
		clear: both;
	}
</style>

  上面這個例子,最終li會被清浮動分割成幾行?

   最終結果是:兩行,如下所示。

  我們用所學的理論知識來解釋下為什麼是兩行,在樣式表中,第三個浮動元素使用了清浮動的屬性,此時,根據標準,當前元素不能和前面的浮動元素相鄰,也就是第三個元素不能和第二個元素做朋友了,那隻能換行了,然而標準沒有規定第三個元素不能和後面的元素做朋友,因此第三個元素以及之後的元素依舊保持左浮動的特性規則排列。由於第一行和第二行都保持了浮動的特性,因此高度全部坍塌,此時父級容器div的高度依舊是0,不會因為清了浮動,父容器的高度就變成第一行的高度了,父容器高度依舊是0!注意是0!

  看完了上面的例子,再來簡單瞭解下clear的四個屬性,分別是none(預設,就是沒有),left(清左浮動),right(清右浮動)以及我們最常用的both(全清)。作者這裡給出了clear的基本使用方式就是clear:both。left和right屬性根本沒有軟用,讓CSS自己判斷就好了,因為不可能有一個元素既是left又是right浮動的,因此無需考慮是清左浮動還是右浮動,全清就完事了。

  由於clear只能確保和前面的元素髮生關係,因此我們最常使用的是after偽類清浮動,而不是before,因為before生成的元素根本沒法和後面的元素交流clear的事情。最後我們放上我們最喜歡使用的after偽類清浮動的方法,注意clear屬性只有塊級元素才有效,而偽類的預設屬性是內聯值,不要忘了display:block申明。

<div class="clearfix">
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
	<div class="li"></div>
</div>
<style>
	.li{
		float: left;
		margin: 10px;
		width: 40px;
		height: 40px;
		background: yellow
	}
	.li:nth-of-type(3){
		clear: both;
	}
	.clearfix::after{
		content: '';
		display: block;
		clear: both;
	}
</style>

 

  本章到這裡其實還沒有結束,下一章的內容會繼續探討float的BFC特性,以及如何用overflow真正的清除浮動。

  其實我自己也還沒看,只是做個預告,感興趣的關注下吧~