你從來沒了解過的CSS浮動 | Design Shack

果凍tfzwgd發表於2019-04-18

浮動到底是做什麼呢?他們是如何影響相關元素的盒模型的呢?浮動的元素與內聯元素有什麼不同呢?制定浮動元素的位置的具體規則是什麼?clear屬性是如何工作的,並且它的作用是什麼?

即使是經驗豐富的開發者也會在浮動上出錯,所以理解浮動的行為能幫你擺脫面對CSS的很多困擾。即使你認為你已經瞭解了關於浮動的所有知識,我們也會深入到你可能會學習到新知識的地步。

什麼是浮動?

在CSS中一些元素是塊級元素,他們會自動啟用新的一行。例如,如果你建立2個單獨的單詞段落元素,它們不會相互流入而會各自出現在單獨的一行。另一種元素是內聯元素,它們會與之前的內容保持顯示在“一行”。舉個例子,有個錨標籤,它可以出現在像段落這個元素之內而且不會造成任何額外的空白,也不會另起一行。

改變這種佈局模型的一種方式是使用浮動,它允許給定的元素挪動到它那一行的一側,並且其他內容向下流動。一個右浮動的元素將被推動直到它的容器的右側,並且內容會沿著它的左側向下流動,一個有浮動的元素會被挪動到左側,內容會沿著它的右側向下流動。

有一個經典的例子是當你將一張圖片放進一段落裡,並且想讓兩者並排出現而不是堆疊。首先,我們用HTML建立兩個元素:

<img src="http://lorempixum.com/200/200/" />
<p>Lorem ipsum...</p>複製程式碼

僅僅這樣並不能出現我們想要的效果。段落元素是一個塊級元素,它會獨自佔一行,所以段落和圖片會顯示在正常的文件流。

你從來沒了解過的CSS浮動 | Design Shack

我們可以通過將圖片浮動到右邊來改變顯示。這種CSS非常基礎:

img {
    float: right;
    margin: 20px;
}複製程式碼

有了這段程式碼,我們的圖片會被挪到它這一行的右邊,段落文字會在它的左邊向下流動。

你從來沒了解過的CSS浮動 | Design Shack

有趣的是,這張圖片在被浮動時,我們其他的內容將會盡可能的嘗試圍繞它出現。如果改變我們容器的大小或者將瀏覽器視窗變窄,文字只是簡單的自我重排而不會觸碰到圖片。

你從來沒了解過的CSS浮動 | Design Shack

這種盒子是怎麼工作的

可能你對這種行為已經有了很好的理解。然而,為了更充分利用浮動,你需要更深層次的理解這兩個元素之間的互動。例如,我們怎麼在段落和圖片之間新增額外的空白?你可能認為這樣可行

p {margin: 20px;}複製程式碼

然而,這不會在圖片和段落之間產生甚至一畫素額外的空白。相反,我們為圖片應用了這些空白:

img {margin: 20px;}複製程式碼

你從來沒了解過的CSS浮動 | Design Shack

你應該問自己一個問題,“為什麼?”為什麼增加段落的margin不會在圖片和段落之間增加空白?因為我們沒有掌握屬於段落的盒模型。

如果你曾懷疑你的佈局是怎麼在基本層面上工作的,試著應用一兩個邊框來看看將發生什麼。如果我們在這個段落上這樣做,結果可能會讓你驚訝,

p {
    border: solid 1px black;
}複製程式碼

你從來沒了解過的CSS浮動 | Design Shack

正如你所看到的,圖片實際上在段落的盒子裡面!這解開了我們的邊界空白疑惑。我們給段落新增的任何空白都被應用到了圖片的右邊,這就是為什麼在圖片和段落之間不會增加空白。

如果我們想改變這種行為,讓段落不再圍繞圖片,我們可以讓段落浮動到左邊,並給他指定寬度(沒有表示寬度,段落將會是100%的寬,將不會佈置在圖片旁邊)。

你從來沒了解過的CSS浮動 | Design Shack

瘋狂的浮動規則

現在我們知道了浮動是做什麼的,以及它是怎麼影響所涉及的元素的盒子的。讓我們繼續討論另一塊可能很多開發者都不瞭解的資訊:控制浮動元素位置的規則。

通常在圖片集或者特徵列表中開發人員會用浮動來控制列表項的位置。我們建立一個簡單的純圖片的列表來看看這是怎麼工作的。

<ul>
  <li><img src="http://placehold.it/100x100&text=1"/></li>
  <li><img src="http://placehold.it/100x150&text=2"/></li>
  <li><img src="http://placehold.it/100x100&text=3"/></li>
  <li><img src="http://placehold.it/100x100&text=4"/></li>
  <li><img src="http://placehold.it/100x100&text=5"/></li>
  <li><img src="http://placehold.it/100x150&text=6"/></li>
  <li><img src="http://placehold.it/100x100&text=7"/></li>
</ul>複製程式碼

預設情況下,所有的列表項都顯示在一個大的垂直棧裡,這意味著它們是塊級元素。即使圖片是內聯元素,它們也被它們的父塊級元素列表項控制。為了解決這種問題,我們要使列表項左浮動。當一行中多個元素被浮動,它們會產生同內聯元素的流類似的效果。然而,正如我們所看到的,有一些關鍵的區別。

li {
    float: left;
    margin: 4px;
}複製程式碼

現在,如果我們所有的圖片都是同樣的高度,這只是一個非常普通的例子。這個結果看起來就像是一個簡單的從左到右按順序排列的圖片集:

你從來沒了解過的CSS浮動 | Design Shack

然而,我們的圖片並不是同樣的高度,一些高100px,其他的高150px。這會造成非常古怪的結果。

你從來沒了解過的CSS浮動 | Design Shack

我第一次看到這種結果的時候感到很困惑。這裡的世界到底發生了什麼?為什麼圖片4會像那樣在右邊?難道它不應該自己試著儘可能讓自己浮動到左邊?如果我們去掉這些列表項的浮動,用display:inline來替代,結果是截然不同的。

li {
  display: inline;
}複製程式碼

你從來沒了解過的CSS浮動 | Design Shack

跟最開始相比,這個例子的不同之處在於圖片的預設狀態是沿著它們的底部邊緣垂直對齊。這會使它們同之前的例子看起來非常不一樣,但是我們可以使用一行CSS來解決這個問題:

img{
    vertical-align: top;
}複製程式碼

現在看起來比較像浮動示例了,只會顯示有一個可預測順序的內聯列表項。當x軸沒有下一項的空間時,它會返回到下一行的左側。

你從來沒了解過的CSS浮動 | Design Shack

所以,我們的浮動圖片集為什麼沒有像這樣顯示呢?為什麼浮動的列表項被奇怪的巫術控制?

九條規則

事實證明,CSS規範列出了九條規則來規定浮動的行為。這個清單的問題在於即使是被寫出來了,也只有無聊的人才能去理解它。這裡是一個從其中一個規則中引用的:

“If the current box is left-floating, and there are any left-floating boxes generated by elements earlier in the source document, then for each such earlier box, either the left outer edge of the current box must be to the right of the right outer edge of the earlier box, or its top must be lower than the bottom of the earlier box. Analogous rules hold for right-floating boxes.”

也許你的閱讀理解能力比我要強,但是這個還有其他的規則都讓我頭暈。所有說什麼左外邊緣在右外邊緣的右邊的言論都是非常平常的東西,卻被裝扮得聽起來十分複雜。為了你們的方便,Josh Johnson將浮動表現翻譯成英文並總結了九條規則,看起來更簡單一點。

  1. 浮動元素會被推到他的容器的邊緣。
  2. 任何浮動元素都會出現在他之前的浮動元素的旁邊或是下方。如果元素都是左浮動,那麼第二個元素將會出現在第一個元素的右邊,如果都是右浮動,第二個元素會出現在第一個元素的左邊。
  3. 左浮動的盒子不能出現在右浮動盒子的右邊。
  4. 浮動元素不能高過他的容器的上邊緣(當涉及到塌陷的邊距這將會更復雜,請參考最初的規則)。
  5. 浮動元素不能比前一個塊級元素或浮動元素高。
  6. 浮動元素不能高過前一行內聯元素。
  7. 靠著另一個浮動元素的浮動元素不能超出自己的父容器邊緣。
  8. 一個浮動的盒子必須儘可能的高的放置。
  9. 一個左浮動的盒子必須儘可能左的放置,一個右浮動的盒子要儘可能的右的放置。儘可能高的位置的優先順序比左右高。

我們可以看做這些大多數都是常識,但他們也要被明確宣告出來以便每個人在每個瀏覽器上看到同樣的頁面。基本上來說,這種情況的要點就是浮動元素會被指定到具體的邊緣(左或者右),沒有過多的要求。除非在他之前有另一個浮動元素,他就會與那個浮動元素相鄰。

真正讓我們感到困惑的是最後的規則,它表明了浮動元素儘可能的保持高的位置,並且垂直定位規則比水平的左右規則在將元素推到邊緣時優先順序更高。

在我們之前的例子中,數字2的圖片把行的高度撐開了,以至於在數字3圖片之後仍然有一些垂直的空間使得數字4圖片擠了進去。即使是考慮到這些規則,這種模式也不容易被預測到。

請記住,當你有一個浮動元素時,後面緊接著的浮動元素至少要佔據與之前同樣或者更多的垂直高度來打破這一行使得流動下移。

你從來沒了解過的CSS浮動 | Design Shack

浮動順序

關於我們在這裡提出的規則的最後一點。第2條規則會對那些浮動元素產生有趣的影響。假設,我們有六張從一到六的數字圖片,如下:

<ul>
  <li><img src="http://placehold.it/100x100&text=1"/></li>
  <li><img src="http://placehold.it/100x100&text=2"/></li>
  <li><img src="http://placehold.it/100x100&text=3"/></li>
  <li><img src="http://placehold.it/100x100&text=4"/></li>
  <li><img src="http://placehold.it/100x100&text=5"/></li>
  <li><img src="http://placehold.it/100x100&text=6"/></li>
</ul>複製程式碼

如果我們將這些圖片浮動到左邊,他們會按順序出現,從一開始直到六,從左到右,從上到下。但是,如果我們將這些圖片右浮動。

你從來沒了解過的CSS浮動 | Design Shack

正如你所看到的,第一張圖片被放到了最右邊的位置。類似的,在換行時,第四張圖片也被放置到了右邊。這就是為什麼你很少看到有人將導航元素右浮動。弄出了這樣螺旋狀的順序就需要HTML結構做出不受歡迎的改變來解決。

清除浮動

浮動對於完成一些類似於創造內容列這樣的佈局很有用。但是,一旦浮動被宣告,他們就會對剩下的文件的產生一些或許你喜歡或者不喜歡的影響。例如,我們想在我們之前提及的那種左浮動的列表塊之後加一個段落。

你從來沒了解過的CSS浮動 | Design Shack

結果或許並不是你所期望的:你從來沒了解過的CSS浮動 | Design Shack

這裡的結果是使用clear屬性,讓沒有浮動的元素可以出現在他所應用的元素給定的一側。例如,比如我們在我們的小相簿列表的第二項新增clear: left.

ul li:nth-child(2) {
  clear: left;
}複製程式碼

這段程式碼告訴瀏覽器,第二項的頂部必須位於他之前的任意左浮動項的底部之下(在這個例子中,是第一項)。如果我們將所有元素都右浮動,我們就要使用clear: right。

你從來沒了解過的CSS浮動 | Design Shack

請注意,在此之後,剩下的浮動元素都會保持他們的位置。因為他們仍然被設定的左浮動,清除屬性並沒有取消他們的表現。這意味著我們的問題不能通過清除列表任意項的浮動來解決。

你從來沒了解過的CSS浮動 | Design Shack

相反,必須被清除的是段落元素,他是一個沒有被浮動的塊級元素。這將確保他會出現在浮動元素的下面而不是旁邊。

p {
    clear: both;
}複製程式碼

從技術上來講,我們只需要清除這裡的左浮動,但是當一個開發者想要確保清除所有浮動時,通常會看到clear的值被設定為both。這個變化能非常好的解決我們的問題。

你從來沒了解過的CSS浮動 | Design Shack

浮動的怪癖和清除浮動

當一個給定的元素只包含浮動元素時會產生奇怪的現象:父元素的高度會坍塌。舉例說明,假設我們想在所有示例中的無序列表給定背景色。如果列表的元素沒有被浮動,我們就只需要應用一下CSS來新增背景。

ul {
    background: gray;
}複製程式碼

正如你所看到的,定義的無序列表的框已經變成了灰色,並且列表中的每一項都堆疊在一起。

你從來沒了解過的CSS浮動 | Design Shack

然而,在第二個例子中,我們浮動了所有列表項,UL只包含了浮動的元素,導致它的高度坍塌,這會讓新手開發者驚訝它的背景色到底發生了啥。

你從來沒了解過的CSS浮動 | Design Shack

有一些方法可以解決這個問題,最簡單容易的方法是為無序列表的父元素明確指定高度。

ul {
  height: 300px;
}複製程式碼

你從來沒了解過的CSS浮動 | Design Shack

正如你所看到的,這的確能讓我們的背景重新被填滿。然而,從長遠來看這並不是一個可取的辦法,如果高度是基於內容自動計算的話。如果我們要新增三個或者更多的圖片到列表庫裡,高度就會不足。

為了解決而清除浮動

這裡術語clear fix,也叫clearfix,就開始發揮作用啦。清除浮動通過使用clear屬性來解決高度坍塌的問題。

開發者在他們的HTML中建立一個跟浮動元素同級的空元素(常常是一個div),然後給空容器新增一個命名為clearfix的class。我們回到CSS中,給clearfix新增清除浮動的屬性。

.clearfix {
  clear: both;
}複製程式碼

立刻就解決了高度坍塌的問題:

你從來沒了解過的CSS浮動 | Design Shack

根據我們已經學過的可以知道為什麼這個方法可以解決我們的問題。高度坍塌的原因是因為父元素只包含了浮動元素的,現在他有了一個子元素,儘管這個子元素是空的,但是它沒有浮動,所以高度會再次跟預期一樣自動生成。

這個方法有個問題是,沒有人喜歡HTML中額外的醜陋的元素。它根本不是語義的,意味著它不能清晰的傳遞頁面的層次結構。

新的解決方案是利用overflow屬性,這個屬性控制了超出其包含框邊界的內容的功能。如果你將父專案的overflow設定為hidden或者auto,也能解決高度坍塌。

ul {
  overflow: auto;
}複製程式碼

你從來沒了解過的CSS浮動 | Design Shack

這絕對是解決高度坍塌問題的最簡單、最優雅的方案,也應該是你的方案。雖然這麼說,那在某種情況,你想將元素的overflow設定為visible,你又應該怎麼做呢?

這樣的結果可以使用Nick Gallagher的微型清除浮動hack,他使用了一下天才般的CSS來解決這個問題。首先,他是使用的:before以及:after來新增一些內容,我們可以用來為父元素建立一些不浮動的元素。然而,你不想在這裡使用真實的內容,所以我們使它為空並且設定display為table來建立一個匿名框(空的而且不佔空間)最後使用我們的老朋友clear。它建立了一個不可見的塊級元素來解決高度坍塌的問題並且沒有新增額外的HTML。IE的老版本需要自己修復。

/* For modern browsers */
.cf:before,
.cf:after {
    content:"";
    display:table;
}

.cf:after {
    clear:both;
}

/* For IE 6/7 (trigger hasLayout) */
.cf {
    zoom:1;
}複製程式碼

結論

文章中,我們討論了大量的資訊,包括基礎和複雜的。我們從最開始討論如何浮動,以及他們在基本層級是如何工作的,然後是如何設定元素的浮動來影響元素所涉及的盒子邊框,讓你找出怎麼樣工作才能根據你想的那樣獲得邊距。

接著,我們討論了浮動元素的基本規則,並得出了一些有趣的結論,就是不同高度的浮動元素如何定位,以及右浮動的元素怎麼以相反的順序出現。

如果在閱讀本篇文章之前,浮動讓你感覺到很困惑,那麼開始閱讀吧。它們最開始就迷惑了我們。希望你現在以及瞭解了浮動是怎麼工作的,以及知道如何使用它們來實現你想要的佈局。如果你覺得這些資訊有幫助,請在下面留下評論讓我們知道。

你從來沒了解過的CSS浮動 | Design Shack


相關文章