1. 程式人生 > >CSS浮動,你不知道的事

CSS浮動,你不知道的事

浮動到底做了什麼?

浮動如何影響元素的盒模型?

浮動的元素和行內元素有何不同?

調整浮動元素的位置是通過什麼規則進行的?

clear屬性如何工作,它的目的又是什麼?


浮動甚至能絆倒有經驗的開發者,理解浮動能幫助你解決很多CSS問題。即使你認為已經知道了浮動的所有知識,我們足夠深入的分析也許也能讓你學到一些新東西。


什麼是浮動?

CSS中的一些元素是塊級元素,表示它們會自動另起一行。

舉個例子,如果你建立了兩個段落,每個段落都只有一個單詞。這兩個單詞不會靠在一起,而是會各自佔據一行。


另一些元素是行內元素,表示它們和前面的內容位於相同的一行。

舉個例子,<a>可以出現在另一個元素中,比如<p>,這不會產生多餘的空格或者出現換行。


欺騙這種佈局模型的一種方式是使用浮動,浮動可以讓一個元素移到它所在行的某一邊,使得其他內容沿著該元素的邊緣向下流。


一個典型的例子是你想要一張圖片和一個段落並排出現,而不是一上一下排列。首先我們先來建立HTML:

?

<img src="http://lorempixum.com/200/200/" />

<p>Lorem ipsum...</p>


單獨這段程式碼並不能實現我們想要的效果。<p>是一個塊級元素,它會獨佔一行,所以圖片和段落是一上一下展現的。 

 
通過讓圖片向右浮動可以改變這種行為,如下:

?

img {

    float: right;

    margin: 20px;

}


這樣,圖片就跑到右邊去了,而段落則沿著圖片的左邊向下流式佈局。


現在發生了一件有趣的事,當這張圖片浮動後,其他的內容就會想辦法儘可能的包圍它。如果我們resize容器或者瀏覽器視窗,讓它更窄,這段文字就會發生重排(reflow),這樣它就永遠不可能接觸到圖片。


盒模型如何工作

也許你已經對上面所講的知識有了深刻的理解。但是,為了完全掌握浮動,你需要更加深刻的理解兩個元素如何互相作用。舉個例子,如果我們在段落和圖片之間加一個邊距會發生什麼?

?

p {margin: 20px;}


但是呢,這麼寫並不會在圖片和段落之間產生額外的空間。實際上,我們需要給圖片加margin:

?

img {margin: 20px;}

 

 

也許你會問為什麼呢?為什麼增加<p>的margin不會增加圖片和段落的間距呢?

原因是我們沒有理解<p>的盒模型。

  
如果現在你對佈局產生了一些疑慮,可以試著加一個或者兩個border,看看會發生什麼。下面給<p>加border:

?

p {

    border: solid 1px black;

}


如你所見,圖片實際上位於<p>盒模型的內部!這就可以解釋剛才的margin問題。我們加到<p>上的margin其實是作用於圖片的右側,這就是為什麼它不能增加圖片和段落之間的距離!


如果我們想改變這種行為,使得段落不會包圍圖片,我們應該讓段落向左浮動,並設定一個寬度(如果不設定,<p>的寬度預設是100%,這樣就不會和圖片緊挨著了,因為如果段落很長,它會跑到下一行)。

?

img {

    float: right;

    margin: 20px;

}

  

p {

    float: left;

    width: 220px;

    margin: 20px;

}

 


瘋狂的浮動規則

現在你知道什麼是浮動了,並且知道浮動如何影響相關元素的盒模型。接下來要說的也許很多人都不瞭解:如何調整浮動元素的位置


web開發中很多人會給<li>使用浮動。下面來看一個例子:

?

<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>預設應該是垂直方向上排列的,這就表示<li>是塊級元素。即使圖片是行內元素,它也會被它的父級塊級元素管理。為了解決這個問題,我們讓<li>向左浮動。當一行內的多個<li>被浮動後,它們會產生類似行內元素的流式佈局。然而,正如你即將看到的,它們有一些關鍵的不同。

?

li {

    float: left;

    margin: 4px;

}


現在,如果所有圖片的高度相同,就會產生下面的效果。


但是,我們的圖片高度不是一樣的,一些是100px,另一些是150px。這就引起了一些嚴重的問題!


當我第一次看到這個效果,我蛋疼了。為什麼圖片4跑到右邊去了?它不是應該儘可能的向左浮動麼?如果我們放棄浮動而使用display:inline,結果會大不一樣。

?

li {

    display: inline;

}

 


這個例子中,圖片預設是垂直居底(bottom)對齊。這和我們之前的例子不同,為了解決對齊問題,我們新增一行CSS。

?

img {  

    vertical-align: top;

}


由此可知,使用display:inline 可以更容易猜到<li>的排列結果。當水平方向沒有多餘的空間時,下個元素就會另起一行。


浮動為什麼不能實現這種效果呢?


CSS規範對於浮動行為概括了9個規則。但問題是,只有規範的作者和那些無聊的人才能理解這些規則。下面摘錄了其中一個規則:

“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給出了他的9條規則(注:我覺得這位仁兄的9條規則依然很囉嗦,我再給精簡一下):

1. 浮動元素的活動區域

  僅限於它的父容器元素,不會超出父容器

2. 浮動元素的位置

  水平方向:儘可能居左或居右,如果它前面還有浮動元素,會跟在它後面,如果超出該行就會換行

  垂直方向:儘可能的居頂

 

關於水平方向的位置,需要注意以下幾點:

1) 向左浮動的元素不會出現在向右浮動的元素的右側

 

關於垂直方向的位置,需要注意以下幾點:

1) 浮動元素不會比容器的頂部還高

2) 浮動元素不會比前一個塊級元素或浮動元素更高

3) 浮動元素不會比前一個行內元素更高

 

在佈局時,垂直方向的規則比水平方向的優先順序更高


總的來說就是,浮動元素會移到左側或右側。除非該元素前面還有一個浮動元素,這時它就會緊挨著前面的元素。


真正讓人迷惑的是:浮動元素會盡可能的居頂,並且垂直定位規則比水平浮動規則的優先順序更高。


在前面的例子中,圖片2撐高了該行的高度,所以在放完圖片3後,仍然有足夠的垂直空間放置圖片4。


記住,當你有一個浮動元素(不位於尾行)時,它後面的浮動元素佔用的垂直空間必須大於或等於它才會觸發換行


浮動順序

舉個例子,我們有6張圖片的一個列表。

?

<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>


如果我們向左浮動圖片,它們就會按照原來的順序排列。但如果向右浮動呢?


可以發現,第一張圖片佔據了最右的位置。類似的,換行後,第四張圖也佔據了最右的位置。這就是為什麼你很少看到導航欄的列表項會向右浮動的原因。


清除浮動

使用浮動可以方便的實現一些佈局,比如建立n欄內容。但是呢,一旦使用浮動就會影響文件正常的流式佈局。比如,剛才那個例子中,我們想在列表下方加上一個段落。


這個結果也許不是你想要的。這裡的解決方法是使用 clear 屬性,它的作用是清除該元素某側的浮動。比如,我們對第二個列表項使用clear:left

?

ul li:nth-child(2) {   

    clear: left;

}

 

這段程式碼告訴瀏覽器第二項的頂部必須比它前面的浮動元素的底部更低。如果所有列表項是向右浮動的,則需要使用clear: right


加上段落文字再看


很明顯這依然不是我們想要的效果,解決方法是給段落使用clear,這會使得段落出現在浮動元素的下方而不是與它們相鄰。

?

p {

    clear: both;

}


其實這裡我們只需要清除左側的浮動即可,但是當一個開發者為了確保清除了所有浮動,clear:both是很常用的一種方法。

浮動的問題和clearfix

當一個元素只包含浮動元素時,該容器元素會出現高度重疊(和高度為0的效果一樣,即高度的頂邊和底邊重疊)。為了演示這個現象,我們還是使用剛才的例子,只是給列表加一個背景色。

?

ul {

    background: gray;

}

  

如果列表項沒有浮動,可以看到整個列表都是灰色的,而列表項則是從上到下排列。


現在我們浮動所有列表項,這時<ul>只包含浮動的元素,所以它的高度重疊了,新手肯定會好奇背景色到底哪去了.


解決這個問題有好幾種方法,最簡單的一種是直接給容器元素設定高度。

?

ul {

    height: 300px;

}

 

這樣背景色又回來了。但是,這種方法常常不能讓我們滿意,因為當我們需要容器的高度和內容自適應時,這種方法完全無效。如果我們再加上三個列表項,這個高度又不夠了。


召喚clearfix

現在該輪到clearfix登場了,它通過clear屬性解決了高度重疊的問題。


我們常常會建立一個空元素(通常是div),它和浮動元素同級,然後給它設定class為“clearfix”。回到CSS,我們加上這樣一行樣式:

?

.clearfix {

    clear: both;

}


這樣就解決了高度的問題。

說下原理:我們知道當元素只包含浮動元素時,高度發生重疊(效果和高度為0一樣),這時該元素有了一個子元素,即使它是個空元素,但它沒有浮動,而且還清除了所有浮動,所以這個空元素會出現在所有元素的下方,從而撐起了容器的高度,於是height:auto恢復正常了。


這種方法的缺點是,HTML中多了一個額外的元素,不符合語義化的思想。


新的解決方法是使用 overflow 屬性,如果你設值為hidden 或 auto,也可以解決高度重疊的問題。

?

ul {

    overflow: auto;

}

 

這種方法更簡單也更優雅,但是還有個問題要說下,如果容器元素必須設定為overflow: visible,你又該怎麼辦呢?


方法是首先使用 :before 和 :after 在元素內建立一些不浮動的東西,但實際上你並不希望出現任何多餘的東西,所以我們設定一個空字串,但是要設定display:table,這樣就建立了一個匿名單元格(是不是想起了<td></td>?),最後使用老辦法,清除浮動。


為了相容老版本的IE,使用它特有的zoom:1清除浮動。

?

/* For modern browsers */

.cf:before,

.cf:after {

    content:"";

    display:table;

}

  

.cf:after {

    clear:both;

}

  

/* For IE 6/7 (trigger hasLayout) */

.cf {

    zoom:1;

}

  

 轉自: http://designshack.net/articles/css/everything-you-never-knew-about-css-floats/