(中級)圍住浮動元素的三種方法

李鬆峰發表於2012-11-15

本文節選自《CSS設計指南(第3版》。
第1章完全免費試讀,電子書線上熱賣中:http://www.ituring.com.cn/book/1111

以下內容節選自第3章。

浮動元素脫離了文件流,其父元素也看不到它了,因而也不會包圍它。這種情況有時候並非我們想要的,本節向大家傳授三種圍住浮動子元素的方法。記住,這三種方法你都得掌握,這樣才能審時度勢,選擇最合適的一種。

為了演示浮動元素的行為,這種行為對佈局會產生什麼影響,以及解決這個問題的三種方法,我們首先要從一張帶標題的圖片開始。圖片和標籤包含在一個section元素中,而section元素後面跟著一個footer元素。可以把這個footer元素想象成很多網頁底部都會有的與頁面同寬的頁尾。

<section>
    <img src="images/rubber_duck2.jpg">
    <p>It’s fun to float.</p>
</section>
<footer> Here is the footer element that runs across the bottom of the page.</footer>

這樣,你才會知道究竟會發生什麼。圖3-18展示了應用以下規則後的sectionfooter的元素盒子。

section {border:1px solid blue; margin:0 0 10px 0;}
/*刪除預設的上下外邊距*/    
p {margin 0;}
/*為簡明起見,省略了字型宣告*/
footer {border:1px solid red;}

enter image description here
圖3-18 可以看到頁面中的兩個塊級元素sectionfooter,前者包含一張圖片及標題,後者在正常文件中位於前者下方

現在我們看到的是正常文件流,即塊級元素包圍著所有子元素,而且在頁面中自上而下相互堆疊在一起。假設我們想讓圖片標題位於圖片右側,而不是像現在這樣位於下方。運用剛剛學到的知識,我們知道實現這個目標最簡單的方式就是浮動圖片。試試看吧。

section {border:1px solid blue; margin:0 0 10px 0;}
img {float:left;}
footer {border:1px solid red;}

圖3-19展示了結果。

enter image description here
圖3-19 浮動圖片後標題跑到了右邊,但父元素section也收縮到只包含文字的高度高度

媽呀!標題倒是跑到右邊了,可section也不再包圍浮動元素了,它只包圍非浮動的元素。於是,footer被提了上來,緊挨著前一個塊級元素——section。這樣是沒錯兒,可結果呢,不是我們想要的。

方法一:為父元素新增overflow:hidden

第一個方法很簡單,缺點是不太直觀,即為父元素應用overflow:hidden,以強制它包圍浮動元素。

section {border:1px solid blue; margin:0 0 10px 0; overflow:hidden;}
img {float:left;}
p {border:1px solid red;}

overflow:hidden宣告應用到容器元素後,footer又回到了我們期望的位置,如圖3-20所示。

enter image description here
圖3-20 給容器元素應用overflow:hidden宣告後,它又包圍了浮動元素

實際上,overflow:hidden宣告的真正用途是防止包含元素被超大內容撐大。應用overflow:hidden之後,包含元素依然保持其設定的寬度,而超大的子內容則會被容器剪下掉。除此之外,overflow:hidden還有另一個作用,即它能可靠地迫使父元素包含其浮動的子元素。

方法二:同時浮動父元素

第二種促使父元素包圍其浮動子元素的方法,是也讓父元素浮動起來。

section {border:1px solid blue; float:left; width:100%;}
img {float:left;}
footer {border:1px solid red; clear:left;}

浮動section以後,不管其子元素是否浮動,它會緊緊地包圍(也稱收縮包裹)住它的子元素。因此,需要用width:100%再讓section與瀏覽器容器同寬。另外,由於section現在也浮動了,所以footer會努力往上擠到它旁邊去。為了強制footer依然呆在section下方,要給它應用clear:left。被清除的元素不會被提升到浮動元素的旁邊。以上程式碼能得到與圖3-20相同的效果。

方法三:新增非浮動的清除元素

第三種強制父元素包含其浮動子元素的方法,就是給父元素的最後新增一個非浮動的子元素,然後清除該子元素。由於包含元素一定會包圍非浮動的子元素,而且清除會讓這個子元素位於(清除一側)浮動元素的下方,因此包含元素一定會包含這個子元素——以及前面的浮動元素。(這一句原文交待不清,譯文增加了一句。——譯者注)在包含元素最後新增子元素作為清除元素的方式有兩種。

第一種方式不太理想,也就是簡單地在HTML標記中新增一個子元素,並給它應用clear屬性。由於沒有預設的樣式,不會引入多餘空間,div元素很適合這個目的。

<section>
    <img src="images/rubber_duck.jpg">
    <p>It's fun to float.</p>
    <div class="clear_me"></div>
</section>
<footer> Here is the footer element…</footer>

在此,我為div新增了一個類,以便於在CSS中新增它。SS

section {border:1px solid blue;}
img {float:left;}
.clear_me {clear:left;}
footer {border:1px solid red;}

這樣,浮動的元素被父元素包圍住了,結果如圖3-20所示。如果你特別不想新增這個純表現性元素,我再告訴你一個用CSS來新增這個清除元素的方法。首先,要給section新增一個類。

<section class="clearfix">
    <img src="images/rubber_duck.jpg">
    <p>It's fun to float.</p>
</section>
<footer> Here is the footer element…</footer>

然後,再使用這個神奇的clearfx規則!

.clearfix:after {
    content:".";
    display:block;
    height:0;
    visibility:hidden;
    clear:both;
}

這個clearfix規則最早是由程式設計師Tony Aslett發明的,它只新增了一個清除的包含句點作為非浮動元素(必須得有內容,而句點是最小的內容)1。規則中的其他宣告是為了確保這個偽元素沒有高度,而且在頁面上不可見。

1 :after會在元素內容——而不是元素後面插入一個偽元素。——譯者注

使用clear:both意味著section中新增的子元素會清除左、右浮動元素(位於左、右浮動元素下方)。這裡當然可以只用left,但both也適用於將來圖片float:right的情況。

同樣,浮動的元素又像圖3-20所示的一樣被包圍住了。但這次標記裡沒有額外硬編碼的元素。好奇的話,你可以臨時把clearfix規則中的heightvisibility宣告刪除,看一看通過偽元素新增到標記中的句點。

我在自己寫的所有網站中都使用clearfix規則來解決浮動問題,因為浮動是實現多欄佈局(在更多瀏覽器支援CSS3的Multi-column Layout Module之前)唯一最可靠的方式。這一點第5章會跟大家詳細解釋。

好了,該回過頭來作個總結了。要想強迫父元素包圍其浮動的子元素有三種方式,哪三種?

  • 為父元素應用overflow:hidden
  • 浮動父元素
  • 在父元素內容的末尾新增非浮動元素,可以直接在標記中加,也可以通過給父元素新增clearfix類來加(當然,樣式表中得需要相應的clearfix規則)

這三種方法的使用要因地制宜。比如,不能在下拉選單的頂級元素上應用overflow:hidden,否則作為其子元素的下拉選單就不會顯示了。因為下拉選單會顯示在其父元素區域的外部,而這恰恰是overflow:hidden所要阻止的。再比如,不能對已經靠自動外邊距居中的元素使用“浮動父元素”技術,否則它就不會再居中,而是根據浮動值浮動到左邊或右邊了。總之,掌握了這三種技術之後,再碰到需要包圍浮動元素的情況,你有能夠遊刃有餘了。

沒有父元素時如何清除

有時候,在清除某些浮動元素時,不一定正好有那麼個父元素可以作為容器來強行包圍它們。此時,最簡單的辦法就是給一個浮動元素應用clear:both,強迫它定位在前一個浮動元素下方。然而,在空間足以容納多個元素向上浮動時,這個簡單的辦法未必奏效,我們還得另闢蹊徑。

為了演示這種情況,圖3-21展示了一個頁面,其中包含6個元素:3張圖片和介紹它們的3個文字段落。這個頁面佈局是通過浮動圖片實現的,因此在標記中跟在圖片後面的文字會向上走,停靠在浮動圖片的右側。

enter image description here
圖3-21 由於第二段文字下方有空間,所以第三張圖片及說明文字會上浮到第二張圖片右側,這不是我們想要的結果

以下是圖3-21中頁面對應的HTML(為節省版面,刪除了部分文字):

<section>
    <img src="images/rubber_duck3.jpg">
    <p>This text sits next to the image and because the…</p>
    <img src="images/beach_ball.jpg">
    <p>This text is short, so the next image can float up…</p>
    <img src="images/yellow_float.jpg">
    <p>Because the previous image’s text does not…</p>
</section>

相應的CSS如下:

section {width:300px; border:1px solid red;}
img {float:left; margin:0 4px 4px 0;}
/*為簡明起見,省略了字型宣告*/
p {margin:0 0 5px 0;}

我們的目標是讓每段文字停靠在相應的圖片旁邊。然而,第二段文字太短了,都沒有夠到第二張浮動圖片的下沿。這就給下一對兒圖片/段落向上浮動留出了空間。

這個例子中的佈局效果從技術角度看是正確的:第三對兒圖片/段落有條件(有空間)停靠在第二張浮動圖片旁邊,於是它們就毫不客氣地靠了過去。畢竟,浮動元素的使命不就是儘可能地向左上或右上遷移嗎。可這個視覺上的結果卻不是我們想要的。

由於每一對兒圖片/段落都沒有包含元素,在此就無法使用前面討論的“強制父元素包圍”的戰術。不過,我照樣可以使用clearfix規則呀!

.clearfix:after {
    content:".";
    display:block;
    height:0;
    visibility:hidden;
    clear:both;
}

像這樣給每個段落都加上clearfix類:

<section>
    <img src="images/rubber_duck3.jpg">
    <p class="clearfix">This text sits next to the image and because the…</p>
    <img src="images/beach_ball.jpg">
    <p class="clearfix">This text is short, so the next image can float up…</p>
    <img src="images/yellow_float.jpg">
    <p class="clearfix">Because the previous image’s text does not…</p>.
</section>

如圖3-22所示,在每個段落內容的最後新增了“清除子元素”,我們想要的佈局效果實現了。因為第三對兒圖片和段落前面增加了一個清除元素,所以它們就不能再往上走了。注意,我沒有隻給第二個段落新增clearfix類,而是每個段落都加上了一個。如果是真正的網站開發,就得這麼做啊。這樣,無論將來哪個段落的文字高度低於圖片了,頁面佈局都不會被破壞。

說到這兒,相信讀者對floatclear屬性都有了深入理解了。本章最後,再給大家介紹兩個對CSS佈局至關重要的屬性:positiondisplay

相關文章