在網絡上關于CSS的文章中,有時候能聽到“標準流”,“浮動流”,“定位流”等等詞語,還有像“文檔流”,“文本流”等詞,這些流是什么意思?它們是CSS中的一些布局方案和特性。今天我們就來聊一下CSS中的這些流。這篇文章將重點詳細描述浮動流。
簡述
- 文檔流,普通流,標準流,常規流等:這么多名詞實際上指的都是文檔流,即元素在HTML中的位置順序,決定了它在頁面中的位置順序。分為塊級元素和行內元素兩種。
- 文本流:文本流指的文檔中元素(例如字符)的位置順序,即從左到右,從上到下的順序形式。
- 浮動流:浮動流是使用CSS浮動屬性作為布局方式。
- 定位流:定位流是使用CSS定位屬性作為布局方式。
看了簡述還是不清楚各種流的區別與關聯,比如文檔流和文本流看起來差不多,究竟有什么不同?CSS浮動和定位為什么要多加一個“流”字?下面我們一一解答下。
預置CSS
下面的文檔中會出現大量的重復CSS代碼,這里提前進行聲明。后面的所有示例都預先加載了這部分CSS代碼。
.left { /* 左浮動 */float: left;
}
.right { /* 右浮動 */float: right;
}
.red { /* 紅 */background: red;
}
.yellow { /* 黃 */background: yellow;
}
.green { /* 綠 */background: green;
}
.blue { /* 藍 */background: blue;
}
.gray { /* 灰 */background: gray;
}
.pink { /* 粉 */background: pink;
}
.brown { /* 棕 */background: brown;
}
.maroon { /* 褐色 */background: maroon;
}
.purple { /* 紫色 */background: purple;
}
.fuchsia { /* 紫紅 */background: fuchsia;
}
.lime { /* 黃綠 */background: lime;
}
.olive { /* 橄欖綠 */background: olive;
}
.navy { /* 藏青 */background: navy;
}
.teal { /* 青 */background: teal;
}
.aqua { /* 水綠 */background: aqua;
}
.orange { /* 橙 */background: orange;
}
.clear-left {clear: left;
}
.clear-right {clear: right;
}
.clear-both {clear: both;
}
文檔流
文檔流又叫做普通流,標準流,常規流等等,它的英文名是“normal flow”,是HTML默認的布局形式。在未指定使用其它布局時,使用的就是文檔流的布局。在文檔流中分為兩種元素:塊級元素和行內元素。
塊級元素:常見的塊級元素有div和p標簽等。塊級元素會默認占滿橫向全部寬度,在文檔流中從上到下垂直排列。塊級元素的左邊緣與父元素的左邊緣是重合的。
行內元素:常見的行內元素有span和a標簽等。行內元素在文檔流中的寬度為實際內容的寬度,在水平方向從左到右排列。
<html><body><div class="border div-common"></div><div class="border div-common div-width"></div><div class="border div-common div-width"></div>你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS!我是JZ。你好CSS! 我是JZ。<span class="border">我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS!</span></body><style>.border { border: 1px solid red; }.div-common { height: 50px; }.div-width { width: 100px; }</style>
</html>
通過例子可以看到,每個塊級元素獨占一行,從上到下排列。在未設置寬度時,默認占滿橫向全部寬度;即使設置了寬度且剩余空間足夠,也是獨占一行。行內元素則從左到右排列,如果一行不夠,則從下一行左邊開始繼續。
文本流
文本流是指的文本字符從左到右,從上到下的輸出順序。只看說明,感覺文本流和文檔流看起來像是一種東西,但事實上是不一樣的,我們看一個例子。
<html><body><div class="container"><div class="div-common"></div>你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS!我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。</div><div class="container"><div class="div-common left"></div>你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS!我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。</div><div class="container"><div class="div-common div-pos"></div>你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS!我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。</div></body><style>.container { margin-bottom: 50px; }.div-common {height: 50px;width: 100px;border: 1px solid red;}.left { float: left; }.div-pos { position: absolute; }</style>
</html>
這里列舉了三種情況(例子中包含浮動流和定位流,我們后面會單獨介紹):
- 第一種情況就是正常的文檔流,塊級元素單獨占一行,字符文本也單獨一行從左到右排列。
- 我們對塊級元素設置了左浮動。下面的字符文本跑到同一行展示了,因此浮動脫離了文檔流。但是字符文本沒有覆蓋到塊級元素上面,因此沒有脫離文本流。
- 我們對塊級元素設置了絕對定位。可以看到下面的字符文本不止跑到同一行展示了,還出現在塊級元素的下面,因此脫離了文檔流,也脫離了文本流。
CSS的float屬性
關于浮動流,首先來描述一下CSS的float屬性。float屬性即是控制浮動流的主要屬性,一共有三個值。向哪個方向浮動,即是將那個元素放到其容器的哪一側。
- left: 左浮動
- right: 右浮動
- none: 不浮動
基本特性
<html><body><div class="div-common">你好CSS! 我是JZ。你好CSS! 我是JZ。你好<img class="img-common" src="1.jpg" /><span>CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。</span></div><div class="div-common">你好CSS! 我是JZ。你好CSS! 我是JZ。你好<img class="img-common left" src="1.jpg" />CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。</div><div class="div-common">你好CSS! 我是JZ。你好CSS! 我是JZ。你好<img class="img-common right" src="1.jpg" />CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。</div></body><style>.div-common { margin-bottom: 40px; }.img-common {width: 40px;height: 40px;}</style>
</html>
文本中間有一個圖片元素,在不設置浮動時,圖片在文本的中間,在設置了左或右浮動后,圖片到了左側或者右側。還可以看到,原本圖片是占一行,但設置了浮動后,實現了文字環繞圖片展示。
<html><body><div class="div-common">你好CSS! 我是JZ。你好CSS! 我是JZ。你好<img class="img-common left" src="1.jpg" /><img class="img-common left" src="1.jpg" /><img class="img-common left" src="1.jpg" />CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。</div><div class="div-common">你好CSS! 我是JZ。你好CSS! 我是JZ。你好<img class="img-common right" src="1.jpg" /><img class="img-common right" src="1.jpg" /><img class="img-common left" src="1.jpg" />CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。你好CSS! 我是JZ。</div></body><style>.div-common {margin-bottom: 40px;}.img-common {width: 40px;height: 40px;}</style>
</html>
如例子,可以將多個元素設置浮動,浮動到同一側的元素會并排放置,即碰到另一個浮動的元素就停止。
塊級元素浮動
不止行內元素,塊級元素實際上也是可以浮動的。我們舉例看一下:
<html><body><div class="div-common" style="height: 140px"><div class="size-common">1</div><div class="size-common">2</div><div class="size-common">3</div></div><div class="div-common"><div class="size-common left">1</div><div class="size-common left">2</div><div class="size-common right">3</div></div><div class="div-common">CSS! 我是JZ。你好CSS! 我是JZ。<div class="size-common left">1</div><div class="size-common left">2</div><div class="size-common right">3</div><div class="size-common right">4</div></div></body><style>.div-common {height: 60px;padding-top: 10px;border: 1px dotted blue; }.size-common {width: 40px;height: 40px;border: 1px solid red; }</style>
</html>
從例子中可以看到,當未設置浮動時,塊級元素根據文檔流的特點,從上到下排列。當設置浮動之后,塊級元素聚到了一行,左右浮動排列。如果同時存在未浮動的行內元素,則行內元素在中間展示。
display屬性變化
其實不僅如此,原本的行內元素在設置了浮動后,就變成了塊級元素。即float屬性會修改display屬性的計算值(圖源MDN):
<html><body><div class="div-common">CSS! 我是JZ。你好CSS! 我是JZ。<div class="size-common left">1</div><img class="size-common left" src="1.jpg" /><span class="left">左浮動</span><div class="size-common left">2</div><div class="size-common right">3</div></div></body><style>.div-common {height: 60px;padding-top: 10px;border: 1px dotted blue; }.size-common {width: 40px;height: 40px;border: 1px solid red; }</style>
</html>
可以看到span元素的display原本是inline,但設置了浮動之后,計算值就變為block了,img元素的現象也是一樣的。
浮動流與塊級元素
上面僅僅描述了浮動的基本特點,其實浮動的特點還有很多。我們從浮動流與塊級元素的角度,再看看浮動有什么其它特點。
浮動流與塊級文檔流
首先來看一下純塊級元素在浮動流中的表現。
<html><body><div class="div-common"><div class="one"></div><div class="two"></div><div class="three"></div><div class="four"></div></div><div class="div-common"><div class="one left"></div><div class="two left"></div><div class="three right"></div><div class="four right"></div></div><div class="div-common" style="margin-top: 80px"><div class="one"></div><div class="two left"></div><div class="three"></div><div class="four"></div></div><div class="div-common"><div class="one"></div><div class="two right"></div><div class="three"></div><div class="four"></div></div><div class="div-common"><div class="one"></div><div class="two left"></div><div class="three left"></div><div class="four"></div></div><div class="div-common" style="margin-top: 20px"><div class="one"></div><div class="two right"></div><div class="three right"></div><div class="four"></div></div></body><style>.div-common {margin-bottom: 10px;border: 1px dotted blue;}.one {background: red;height: 20px;width: 30px;}.two {background: yellow;height: 50px;width: 40px;}.three {background: green;height: 30px;width: 50px;}.four {background: blue;height: 40px;width: 60px;}</style>
</html>
這里有按先后次序放置的四個元素,分別是第一個紅,第二個黃,第三個綠,第四個藍色。藍色虛線指的是外部容器的框。我們看看它們在不同場景下的表現:
- 第一行:未設置浮動,四個元素按照文檔流從上到下展示。
- 第二行:四個元素全部設置浮動,四個元素排成了一行。在子元素全部為浮動時,父級元素的高度會變為0,子元素無法撐起父元素的高度,造成塌陷。具體的解決方案我們會在后面章節描述。
- 第三行:第一個紅元素是正常文檔流,第二個黃元素設置了左浮動;因此第二個元素的位置是在第一個元素下方。由于黃元素是浮動不占文檔流位置,因此第三個綠元素和第四個藍元素從上到下依次排列。
- 第四行: 在第三行的基礎上,把第二個黃元素設置為右浮動,不擋住其它元素,可以看到非浮動的1,3,4元素組成了一個正常的文檔流。
- 第五行: 第一個元素是正常文檔流。第二個黃,第三個綠元素設置了左浮動,因此在第一個元素下方橫向排列。第四個元素未浮動,因此與第一個元素一起組成正常文檔流。
- 第六行: 在第三行的基礎上,把第二個黃,第三個綠元素設置為右浮動,不擋住其它元素。
通過這幾個例子,可以看到浮動與文檔流的關系。浮動元素前面如果有塊級元素,那么浮動元素會在塊級元素的下方。但是浮動元素本身脫離了文檔流,因此不占空間,下方的非浮動塊級元素可能會被浮動元素蓋住。所有非浮動元素會形成一個文檔流。
塊級元素與浮動超過一行(單側)
當浮動的塊級元素超過一行時,會發生什么現象呢?我們來看一下單側浮動的例子。
<html><body><div class="div-common"><div class="one left"></div><div class="three left"></div><div class="four left"></div><div class="two left"></div><div class="three left"></div><div class="two left"></div></div><div class="div-common" style="margin-top: 110px"><div class="one left"></div><div class="two left"></div><div class="three left"></div><div class="four left" style="width: 100px"></div></div><div class="div-common" style="margin-top: 80px"><div class="one left"></div><div class="two left"></div><div class="three left"></div><div class="four left"></div></div><div class="div-common" style="margin-top: 100px"><div class="one left" style="height: 100px"></div><div class="two left"></div><div class="three left"></div><div class="four left"></div></div><div class="div-common" style="margin-top: 120px"><div class="one left"></div><div class="two left"></div><div class="three left" style="height: 50px"></div><div class="four left"></div></div><div class="div-common" style="margin-top: 120px"><div class="one left" style="height: 100px"></div><div class="two left" ></div><div class="three left" style="height: 50px"></div><div class="four left"></div></div><div class="div-common" style="margin-top: 120px"><div class="one left" style="height: 100px"></div><div class="two left" ></div><div class="three left"></div><div class="four left"></div><div class="two left" style="height: 10px"></div></div><div class="div-common" style="margin-top: 120px"><div class="one left"></div><div class="two left"></div><div class="three left"></div><div class="four left"></div><div class="one left"></div><div class="two left"></div><div class="three left"></div><div class="four left"></div></div><div class="div-common" style="margin-top: 150px"><div class="one left"></div><div class="two left"></div><div class="three left"></div><div class="one left"></div><div class="two left"></div><div class="one left"></div><div class="one left"></div><div class="two left"></div><div class="two left"></div></div></body><style>.div-common {margin-bottom: 10px;border: 1px dotted blue;}.one {background: red;height: 20px;width: 90px;}.two {background: yellow;height: 50px;width: 120px;}.three {background: green;height: 40px;width: 150px;}.four {background: blue;height: 40px;width: 180px;}</style>
</html>
這些例子中為了更容易換行,元素比較寬,且數量比較多,每一個元素都設置的左浮動。例子比較復雜,我們一個一個來分析:
- 第一個例子:正常浮動,超過一行之后,從第二行左邊繼續開始浮動。且第二行的垂直位置是前一行最低的位置。
- 第二個例子:第三個綠元素的高度比第二個矮一點,第四個元素與第三個高度一樣,且一行可以完整放置,因此橫向排列。
- 第三個例子:與第二個例子類似,但是第四個藍元素更寬,導致水平一行肯定放不開。但是注意第四個藍元素并沒有去開一個新行,而是在前一個綠元素下方繼續放置。
- 第四個例子:與第三個例子類似,但是第一個紅元素高度很高,能縱向同時容納第二個黃元素與第三個綠元素。但因為水平有空間,因此第三個綠元素并沒有縱向放置。第四個藍元素雖然水平一行肯定放不開,而且前面的紅元素右側還有大片空閑區域,但是依舊放置在第三個綠元素下方。
- 第五個例子:與第三個例子類似,但是第二個黃元素與第三個綠元素高度相同。因此第三個綠元素下方沒有空閑區域了,因此第四個綠元素只好從最左側開始新的一行浮動了。
- 第六個例子:第一個紅元素非常高,第二三個元素高度相同,且第四個藍元素太寬,無法放置在第一行。由于前一個第二三個元素高度相同,因此第四個藍元素無法放置在第三個下方,因此它向前尋找,找到了第一個元素下方還有位置。
- 第七個例子:與第六個例子類似,但第四個藍元素可以放置在第三個元素下方,同時增加了第五個黃元素。第五個黃元素太寬,無法放置在第四個綠元素右側。第五個黃元素同時高度非常低,三四五元素加起來都比紅元素高度低,因此第五個黃元素向前尋找位置,最終在第一個紅元素右側放置。注意看雖然第五個黃元素上方還有空位可以容納它自己,但是它不在前一個元素右側的時候,它的位置縱向需要在前一個元素下方。
- 第八個例子:第四個藍元素在第三個綠元素下方放置,且依舊屬于浮動的第一行。第五個紅元素的水平位置和第四個藍元素對齊,雖然上方還有位置可以完整放置紅元素,但紅元素還是沒有過去。同樣的第二行的第一個黃元素上方有位置,但縱向還是從上一行最低的位置下方開始。
- 第九個例子:上面部分示例的綜合場景。
從上面的例子可以看到浮動在換行場景時的一些規律:
- 如果一行后方有位置,那么優先水平放置。
- 如果一行后方沒有位置,且前一個元素下方有“空位”,就優先放置在前一個元素下方。如果下方沒有空位,但是更前的元素下方有空位,這個元素會向前尋找。
- 后一個元素的位置如果在前一個元素右側,那么縱向位置可以水平對齊。如果后一個元素的位置如果在前一個元素左側,那么那么縱向位置必須在前一個元素最低位置的下方。
- 如果實在找不到位置,那就開啟新的一行浮動。新一行浮動的縱向位置開始于前一行所有元素的最下方。
塊級元素與浮動超過一行(雙側)
可以看到,在單側浮動的元素排列就已經比較復雜了,如果左側和右側同時出現浮動,且超過一行,又會出現怎樣的現象呢?首先看個簡單的例子。
<html><body><div class="div-common"><div class="div1 left red"></div><div class="div1 left yellow"></div><div class="div1 right green"></div><div class="div1 right blue"></div><div class="div1 left gray"></div><div class="div1 right pink"></div></div><div class="div-common" style="margin-top: 110px"><div class="div1 left red"></div><div class="div1 left yellow"></div><div class="div1 left gray"></div><div class="div1 right pink"></div><div class="div1 right green"></div><div class="div1 right blue"></div></div><div class="div-common" style="margin-top: 110px"><div class="div1 left red"></div><div class="div1 left yellow"></div><div class="div1 left gray"></div><div class="div1 right pink"></div><div class="div1 left green"></div><div class="div5 right blue"></div></div><div class="div-common" style="margin-top: 110px"><div class="div3 left red"></div><div class="div2 left yellow"></div><div class="div2 left gray"></div><div class="div1 right pink"></div><div class="div1 left green"></div><div class="div2 right blue"></div></div><div class="div-common" style="margin-top: 120px"><div class="div3 left red"></div><div class="div2 left yellow"></div><div class="div2 left gray"></div><div class="div1 right pink"></div><div class="div1 left green"></div><div class="div2 right blue"></div><div class="div2 left pink"></div><div class="div2 left gray"></div><div class="div2 right yellow"></div><div class="div2 left green"></div></div></body><style>.div-common {margin-bottom: 10px;border: 1px dotted blue;}.div1 {height: 40px;width: 100px;}.div2 {height: 40px;width: 150px;}.div3 {height: 100px;width: 50px;}.div4 {height: 200px;width: 50px;}.div5 {height: 40px;width: 50px;}</style>
</html>
- 首先看第一與第二個例子:同樣的6個元素,只不過順序和左右浮動不同。這里可以看到換行的規律:按照元素在HTML中出現的順序在頁面中排列,如果第一行無法容納下一個元素,那么就從第二行開始繼續浮動。
- 第三個例子在的第五個綠元素因為第一行位置不夠,因此開啟了第二行左浮動。第六個藍元素是右浮動,雖然第一行有位置可以放置,但由于上一個元素已經開啟了第二行(雖然是左浮動),因此也在第二行展示了。
- 然后是第四個例子,第一個紅元素高度非常高,因此其余的左右浮動元素都在它的右側排列,在內部換行,但是都屬于大的第一行。再看第五個例子,第一個紅元素的右側足夠放置三行元素的排列。尤其看第三行,最上面的部分高度在紅元素內,但是下面的高度已經超過紅元素了。再看最后一個綠元素,當右側位置不夠時,終于開啟了大的第二行浮動。
<html><body><div class="div-common"><div class="div1 left red"></div><div class="div4 right yellow"></div><div class="div2 left gray"></div><div class="div3 right pink"></div><div class="div2 left green"></div></div><div class="div-common" style="margin-top: 150px"><div class="div1 left red"></div><div class="div4 right yellow"></div><div class="div2 left gray"></div><div class="div3 right pink"></div><div class="div2 right green"></div></div><div class="div-common" style="margin-top: 150px"><div class="div1 left red"></div><div class="div4 right yellow"></div><div class="div2 left gray"></div><div class="div3 right pink"></div><div class="div2 right green"></div><div class="div2 right blue"></div><div class="div1 left brown"></div></div><div class="div-common" style="margin-top: 160px"><div class="div5 right red"></div><div class="div1 left yellow"></div><div class="div3 left gray"></div><div class="div6 right green"></div><div class="div7 left pink"></div><div class="div8 left brown"></div></div><div class="div-common" style="margin-top: 160px"><div class="div5 right red"></div><div class="div1 left yellow"></div><div class="div3 left gray"></div><div class="div6 right green"></div><div class="div7 left pink"></div><div class="div8 right brown"></div></div></body><style>.div-common {margin-bottom: 10px;border: 1px dotted blue;}.div1 {height: 50px;width: 100px;}.div2 {height: 50px;width: 150px;}.div3 {height: 40px;width: 100px;}.div4 {height: 40px;width: 300px;}.div5 {height: 100px;width: 150px;}.div6 {height: 40px;width: 150px;}.div7 {height: 80px;width: 100px;}.div8 {height: 100px;width: 50px;}</style>
</html>
再看更復雜一點的例子。
- 首先第一個例子,第一個紅元素比第二個高一點,導致第三個灰元素左浮動時靠在紅元素的右側。而第四個綠元素比第三個灰元素低一點,因此第五個綠元素左浮動時靠在灰元素的右側,形成了類似于臺階的樣式。第二個例子把最后的綠元素右浮動,可以看到和左浮動在同一水平位置。
- 第三個例子在第二個的基礎上增加了右浮動的藍元素。雖然是右浮動,但因為綠元素前面位置水平被灰元素擋住了,因此位置靠下了,這時候藍元素左側反而沒有左浮動的元素了,這時候放置一個左浮動的棕元素,它反而靠在最前了。
- 第四第五個例子非常類似,區別在于最后的棕元素是左浮動還是右浮動。棕元素的前一個元素是左浮動的粉元素,但是棕元素的位置上方恰好空出了一塊位置,可以容納棕元素。但是棕元素不能比前一個元素的水平位置更高,因此上方空出了一塊位置。這個不管對左浮動還是右浮動都有效。
通過這幾個例子可以看到,雙側浮動和單側浮動的換行以及位置規律是一樣的,單側的規則雙側也是可以生效的。但由于雙側浮動情況更多,因此會有更多看起來奇怪的位置排列現象。
不同父元素的浮動流
上面嘗試的例子都集中在一個父元素里面,如果在不同的父元素中浮動,會發生什么現象呢?
<html><body><div class="div-common"><div class="div1 left red"></div><div class="div1 left yellow"></div></div><div class="div-common"><div class="div1 right gray"></div><div class="div1 right pink"></div></div><div class="div-common" style="margin-top: 80px"><div class="div2 left red"></div><div class="div1 right yellow"></div><div class="div1 right pink"></div></div><div class="div-common" style="margin-top: 10px"><div class="div1 left blue"></div><div class="div2 left gray"></div><div class="div1 left green"></div></div><div class="div-devide" style="margin-top: 180px"></div><div><div class="div1 left red"></div><div class="div1 left yellow"></div></div><div><div class="div1 right gray"></div><div class="div1 right pink"></div></div><div class="div-devide" style="margin-top: 100px"></div><div><div class="div2 left red"></div><div class="div1 right yellow"></div><div class="div1 right pink"></div></div><div style="margin-top: 10px"><div class="div1 left blue"></div><div class="div2 left gray"></div><div class="div1 left green"></div></div></body><style>.div-common { border: 1px dotted blue; }.div-devide {border: 1px dotted brown;}.div1 {height: 50px;width: 100px;}.div2 {height: 50px;width: 150px;}</style>
</html>
這幾個例子與前幾個有一些區別:這些都是兩個父級div組成了一個例子,父級div之間沒有設置margin。前兩個例子父級div有border,后兩個例子沒有。
- 第一個例子:兩個父級div由于內部元素全部浮動,因此不占空間。所以內部元素在垂直位置上居然是重疊的。即第二個父級div的元素浮動不會因為第一個父級div元素中出現浮動而在第二行排列。但由于父級div存在border,因此垂直位置并不是完全一致的,而是有很小的高度差。
- 第三個例子:在第一個例子的基礎上去掉了父級div的border。這樣我們發現不同父級的浮動元素在垂直方向上位置完全一致。
- 第二個例子:在第一個例子的基礎上,增加了第二個父級div的margin-top,這樣兩個父級的元素浮動在第一行就能有明顯區分,而且多了幾個元素。我們看第五個灰元素,它自身屬于第二個父級,放置的時候屬于第一個父級的右浮動元素擋住了它的位置。雖然所屬的父元素不同,但是灰元素依然避開了粉元素,在下方放置了。最后一個綠元素因為第一行位置不夠,在第二行重新開始浮動。
- 第四個例子:在第二個例子的基礎上,去掉了父級div的border。現象與第二個例子基本一致。
從這幾個例子可以看出,雖然浮動元素所屬的父級不同,浮動流的規律也是適用的;即在同一個浮動流中浮動。
浮動流與同高度行內元素
上面我們討論了很多塊級元素在浮動流中的現象,現在再討論一下浮動流與行內元素的特點。由于行內元素場景更多,這里僅討論下非可替換與行內塊元素,以及元素高度固定的場景。這里以span元素為例,其它元素的現象也是一致的。
單個行內元素浮動
首先來看一下單個行內浮動元素的表現。
<html><body><div class="div-common"><span class="red">第1個</span><span class="yellow">第2個</span><span class="green">第3個</span><span class="blue">第4個</span><span class="gray">第5個</span></div><div class="div-common"><span class="red">第1個</span><span class="left yellow">第2個左</span><span class="green">第3個</span><span class="blue left">第4個左</span><span class="gray">第5個</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個個個個個個個個</span><span class="left yellow">第2個個個個個左</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="left yellow">第2個個個個個左</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="left yellow">第2個個個個個左</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個</span><span class="yellow">第2個個個個個個個個個</span><span class="left green">第3個個個個個左</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個</span><span class="yellow">第2個個個個個個個個個個個個個個個個個個個個</span><span class="left green">第3個個個個個左</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個個個個個個個個個個個個個個個個個個個個</span><span class="green">第3個個個個個個個個個個個個個個個個個個個個個個個</span><span class="left gray">第4個個個個個個個個個個個</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個個個個個個個個個個個個個個個個個個個個</span><span class="green">第3個個個個個個個個個個個個個個個個個個個個個個個</span><span class="gray">第4個個個個個個個</span><span class="left pink">第5個個個個個個個個</span></div></body><style>.div-common {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
- 第一個例子:五個行內元素,沒有設置浮動
- 第二個例子:第二個和第四個元素設置了左浮動,這兩個元素跑到最左邊了。同樣都是浮動元素時,按照它們的在原HTML中的位置排列。
- 第三個例子:只有兩個元素,第二個元素浮動。但第一個元素太長,使得第一行無法容納下完整的第二個元素,因此跑到第二行最左邊浮動。注意此時第一行雖然有位置,但是浮動元素并未利用。(非浮動時則會利用)
- 第四個例子:只有兩個元素,第二個元素浮動。但第一個元素太長,超過了一行。因此第二個元素跑到第二行最左邊浮動。注意此時第一個元素看起來向被浮動元素“斷成兩截”的樣子。
- 第五個例子:第一個元素太長了,自己延伸到第三行了,因此把第二個元素擠到第三行浮動。
- 第六個例子:前兩個元素使得第一行位置不足了,因此跑到第二行最左邊浮動。注意此時第一行雖然有位置,但是浮動元素并未利用。(非浮動時則會利用)
- 第七個例子:前兩個元素超過了一行,第三個元素跑到第二行最左邊浮動。最后一個元素像是被浮動元素“斷成兩截”的樣子。
- 第八個例子:三個元素延伸到第三行了,因此把第四個元素擠到第三行浮動。
- 第九個例子:四個元素延伸到第三行了,第五個元素擠到第三行浮動。但注意第四個元素自身比較短,是肯定在第三行展示的,因此這里不止截斷了第三個長元素,第一個元素還在同一行的第五個后面。
這里能總結出單個元素單側浮動的一點規律:浮動元素會在當前行向一側浮動。但如果浮動元素在浮動前的位置跨行,則在它最下方所在行浮動。即原來浮動元素可能在第二行和第三行,則浮動后會在第三行浮動。我們做一下更多的實驗,看看總結的規律是否正確。
單個元素很長
這里試一下單個元素很長的場景,包括單個很長的非浮動元素與浮動元素:
<html><body><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow left">第2個</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個</span></div><div class="div-common"><span class="red">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow left">第2個</span></div><div class="div-common"><span class="yellow">第1個</span><span class="red">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="div-common" style="margin-bottom: 70px"><span class="yellow">第1個</span><span class="red left">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="div-common"><span class="yellow">第1個</span><span class="red">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第3個</span><span class="blue">第4個</span></div><div class="div-common"><span class="yellow">第1個</span><span class="red">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green left">第3個</span><span class="blue">第4個</span></div><div class="div-common" style="margin-bottom: 90px"><span class="yellow">第1個</span><span class="red left">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第3個</span><span class="blue">第4個</span></div><div class="div-common"><span class="yellow">第1個</span><span class="red left">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第3個</span><span class="blue">第4個</span><span class="gray">第5個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="div-common"><span class="red left">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個</span><span class="green">第3個</span><span class="blue">第4個</span><span class="gray">第5個個個個個個個個個個個</span></div></body><style>.div-common {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
上面的每個例子共同特征是都有一個超過一行的紅元素。我們一個一個來分析:
- 第一個例子:未設置浮動,與第二個例子做對比用。
- 第二個例子:第二個黃元素設置了浮動,浮動前它在紅元素之后,浮動后截斷了紅元素,跑到第二行最左側了。
- 第三個例子:與第一個例子類似,未設置浮動。只不過紅元素更長了,使得第二個黃元素在第二行換行。
- 第四個例子:第三個例子中的黃元素設置了浮動,可以看到浮動前黃元素橫跨第二行第三行,浮動后只在第三行展示。
- 第五個例子:第一個黃元素與第二個長紅元素橫跨第一行第二行,均未設置浮動。
- 第六個例子:第五個例子中的紅元素設置了浮動,在設置浮動后紅元素從第二行開始展示,一直持續到第三行,且紅色背景的覆蓋范圍持續到第三行結束。
- 第七個例子:一共四個元素,均未設置浮動。其中第二個紅元素很長。
- 第八個例子:第三個綠元素設置了浮動,它本來就在第二行,因此跑到了第二行最左側,截斷了紅元素。
- 第九個例子:一共四個元素,其中第二個紅元素很長,且設置了浮動。可以看到第二個紅元素在第二行第三行展示,和第六個例子一致。
- 第十個例子:在第九個例子的基礎上增加了第五個灰元素,較長且未設置浮動。第二個紅元素右上方的空白被灰元素填充了,且剩下灰元素部分被浮動的紅元素階段,到了第四行展示。
- 第十一個例子:第十個例子中的紅元素跑到了第一位,其它元素都沒有占用紅元素在第二行剩下的空間,而是全部在第三行展示。
上面的例子看似有點奇怪,其實比較容易理解。雖然我們的元素是span,但浮動后就變成了塊級元素,其中的文本也在塊級元素內展示。因此浮動前這些文本可能橫跨兩行,浮動后便統一在一行展示了。即使是避免不了換行的長元素,也是在塊級元素內部換行。也正因為是塊級元素,因此存在換行的長元素的未被文本覆蓋的有背景的位置,也屬于塊級內部,別的文本是不能占用這個位置來展示的。
至于同一個span元素中的文本是可以被浮動元素截斷,導致換行甚至間隔幾行來展示的。另外如果浮動的元素在最下方,父元素的寬高是不計算最下方的浮動元素的。但如果浮動元素在最上方,父元素的寬高卻將它包含在內。
多行內元素單側浮動
上面的例子基本都都是單個元素浮動的場景,這一部分我們來看下多個元素同時浮動的例子。
<html><body><div class="div-common"><span class="yellow">第1個</span><span class="red">第2個</span><span class="green">第3個</span><span class="blue">第4個</span><span class="gray">第5個</span></div><div class="div-common"><span class="yellow">第1個</span><span class="red left">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span></div><div class="div-common"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span></div><div class="div-common"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span></div><div class="div-common"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span></div><div class="div-common"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span></div><div class="div-common"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span></div><div class="div-common"><span class="yellow">第1個個個個個個個個個個個個個個個個</span><span class="red left">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span></div></body><style>.div-common {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
這是一組相互關聯的例子,每個例子都是五個元素。從第二個例子開始,都是第二個和第四個元素浮動。從第三個例子開始,第一個元素變長,但是長度逐漸減小。
- 第一個例子:五個元素沒有浮動,做對照使用。
- 第二個例子:第二和第四個元素左浮動,浮動順序為在HTML中的元素順序。
- 第三個例子:第一個元素超長,導致元素其它元素全部在第二行。浮動的第二和第四個元素也在第二行展示。效果和上一節的例子一致。
- 第四個例子:第一個元素縮短,長度不足占滿一行,但是第一行又不夠完整的展示第二個元素(浮動為了塊級元素,不能像行內元素一樣換行),因此第三個元素的一部分放到了第一行。
- 第五個例子:繼續縮短第一個元素,使得第一行可以容納第二個元素,因此第二個元素在第一行左浮動。
- 第六個例子:繼續縮短第一個元素,使得第一行可以容納第二和第三個元素,但第四個位置不夠,此時第五個元素在第一行和第二行跨行展示。
- 第七個例子:繼續縮短第一個元素,使得第一行可以容納第二,第三,第四個元素。此時第二和第四個元素都在第一行左浮動。
- 第八個例子:繼續縮短第一個元素,此時所有元素都在第一行展示,類似第二個例子。
這個例子體現出的行內浮動規則在前面已經說過了,但是通過不斷地縮短第一個元素,能看出一個有趣的現象:當前行無法容納浮動元素時,浮動元素會在下一行展示。但是排在后面的非浮動元素卻不受限制,可以跑到浮動的前一行展示。
如果排到后面的浮動元素可以在當前行容納下,那么這個元素會不會排到前面展示呢?根據上面塊級元素的規律,我認為不會。我們再看幾個例子實驗下:
<html><body><div class="div-common"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第2個個個個個個個</span><span class="green left">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span></div><div class="div-common" style="margin-bottom: 150px"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green left">第3個</span><span class="blue left">第4個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="gray left">第5個個個</span></div><div class="div-common"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green left">第3個</span><span class="blue left">第4個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="gray left">第5個個個</span><span class="pink">第6個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="div-common"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green left">第3個</span><span class="blue left">第4個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="gray left">第5個個個</span><span class="pink">第6個個個個個個個個個個個個個個個個個個</span></div></body><style>.div-common {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
- 第一個例子:第一個黃元素比較長,導致第二個紅元素雖然是左浮動,但第一行容納不下,因此在第二行左浮動。第三個第四個元素雖然第一行的空間足夠容納下,但它們是左浮動,必須在第二個紅元素下方或者右側,因此只能在第二行紅元素后面放置。
- 第二個例子:第二到第五個元素全部左浮動。其中第二和第四個元素長度超過了一行。可以看到所有浮動的元素都單獨一行,因為所有的元素都沒辦法和前面的元素組合成單獨一行。而且雖然第一行有空位可以容納第三個元素,而且第二個元素后面(第三行)也有空位,但是由于塊級元素的性質以及浮動元素不能出現在前一個浮動元素的“前面”,因此第三個元素依然獨立一行展示。第五個元素同理。
- 第三個例子:增加了第六個非浮動元素,可以看到它在各個浮動元素造成的空白中補足(除了被塊級元素占據的空白)。
- 第四個例子:縮短了第六個元素的長度,使其只到第四行。
可以看到第二個例子中父級元素的的邊框只右第一行,第三個例子中父級元素的邊框持續到了最后一行,第四個例子中父級元素的邊框縮短到了第四行。這說明行內元素構成的浮動中,依然是非浮動元素的高度決定了它的高度。通過這些例子可以看到,塊級元素浮動規律和文本行內元素構成的浮動是一致的。例如后一個左浮動元素必須在前一個左浮動元素的“下方或者右側”(右浮動同理)。
多行內元素雙側浮動
了解了單側多元素浮動,再來看一下雙側多元素浮動的場景。與單側一樣,我們也構造一組相互關聯的例子:
<html><body><div class="div-common"><span class="red">第1個</span><span class="yellow">第2個</span><span class="green">第3個</span><span class="blue">第4個</span><span class="gray">第5個</span><span class="pink">第6個</span><span class="brown">第7個</span></div><div class="div-common"><span class="red right">第1個</span><span class="yellow">第2個</span><span class="green right">第3個</span><span class="blue">第4個</span><span class="gray left">第5個</span><span class="pink">第6個</span><span class="brown left">第7個</span></div><div class="div-common"><span class="red right">第1個個個個個個個個個個個個個個</span><span class="yellow">第2個</span><span class="green right">第3個</span><span class="blue">第4個</span><span class="gray left">第5個</span><span class="pink">第6個</span><span class="brown left">第7個</span></div><div class="div-common"><span class="red right">第1個個個個個個個個個個個個個個個個</span><span class="yellow">第2個</span><span class="green right">第3個</span><span class="blue">第4個</span><span class="gray left">第5個</span><span class="pink">第6個</span><span class="brown left">第7個</span></div><div class="div-common"><span class="red right">第1個個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個</span><span class="green right">第3個</span><span class="blue">第4個</span><span class="gray left">第5個</span><span class="pink">第6個</span><span class="brown left">第7個</span></div><div class="div-common"><span class="red right">第1個個個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個</span><span class="green right">第3個</span><span class="blue">第4個</span><span class="gray left">第5個</span><span class="pink">第6個</span><span class="brown left">第7個</span></div><div class="div-common"><span class="red right">第1個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個</span><span class="green right">第3個</span><span class="blue">第4個</span><span class="gray left">第5個</span><span class="pink">第6個</span><span class="brown left">第7個</span></div><div class="div-common"><span class="red right">第1個個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個</span><span class="green right">第3個</span><span class="blue">第4個</span><span class="gray left">第5個</span><span class="pink">第6個</span><span class="brown left">第7個</span></div><div class="div-common"><span class="red right">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow">第2個</span><span class="green right">第3個</span><span class="blue">第4個</span><span class="gray left">第5個</span><span class="pink">第6個</span><span class="brown left">第7個</span></div></body><style>.div-common {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
- 第一個例子:未設置浮動,做對比用。
- 第二個例子:第一個和第三個元素設置了右浮動,第五個和第七個元素設置了左浮動。可以看到,在HTML中順序靠前的元素在浮動中的順序更靠前。
- 第三個例子:第一個元素長度增加,使得第一行放不開所有元素。這里第七個元素被擠到了第二行。由于第七個元素是浮動元素,因此他沒有跨行展示。
- 第四個例子:第一個元素長度繼續增加。使得第六個元素無法完整放在第一行,由于它不是浮動元素,因此跨行展示。
- 第五個例子:第一個元素長度繼續增加,第六個元素全部放置在第二行。
- 第六個例子:第一個元素長度繼續增加,使得第五個元素無法完全放置在第一行。注意由于第五個元素是左浮動,不能跨行展示,因此在完全第二行展示。但是這樣造成第一行又剩下一點空間被第六個元素填充了。
- 第七個例子:第一個元素長度繼續增加,第五六七個元素都在第二行展示,第四個元素由于空間不夠跨行展示。
- 第八個例子:第一個元素長度繼續增加,第二行完整展示第四個元素。
- 第九個例子:第一個元素長度繼續增加,超過一行。觸發了塊級元素獨立成兩行,其它元素都在第三行展示。
當雙側浮動時,元素的展示與換行規律也是一樣的,浮動元素的出現位置按照HTML的位置順序出現。對于浮動元素來說,位置更靠后的元素的所在行不可能在位置更靠前的元素所在行的前面。但非浮動元素由于可以補缺的原因,位置靠后的元素是可以出現在更前面的行的。我們再來看幾個例子:
<html><body><div class="div-common"><span class="red left">第1個個個個個個個個個個個個</span><span class="yellow right">第2個個個個個個個個個個個個個</span><span class="green left">第3個個個個個個個個個個個個個個個</span><span class="blue right">第4個個個個個個個個</span><span class="gray left">第5個個個個個個個個個</span><span class="pink right">第6個個個個個個個個個個個</span><span class="brown">第7個個個個個個個個個個個個個個個個個個個</span></div><div class="div-common" style="margin-bottom: 100px"><span class="brown">第0個個個個個個個個個個個個個個個個個個個個個個</span><span class="red left">第1個個個個個個個個個個個個</span><span class="yellow right">第2個個個個個個個個個個個個個</span><span class="green left">第3個個個個個個個個個個個個個個個</span><span class="blue right">第4個個個個個個個個</span><span class="gray left">第5個個個個個個個個個</span><span class="pink right">第6個個個個個個個個個個個</span></div><div class="div-common"><span class="red left">第1個個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow right">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green left">第3個個個個個個個個個個個個</span><span class="blue right">第4個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="gray left">第5個個個個個個個個個個個個</span><span class="pink right">第6個個個個個個個個個個</span><span class="brown">第7個個個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="div-common"><span class="red left">第1個個個個個個個個個個個個個個個個個個個個個個個</span><span class="yellow right">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green left">第3個個個個個個個個個個個個</span><span class="blue right">第4個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="gray left">第5個個個個個個個個個個個個</span><span class="pink right">第6個個個個個個個個個個</span><span class="brown">第7個個個個個個個個個個個個個個個個個個個個個個個個個</span></div></body><style>.div-common {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
- 第一個例子:前六個元素分別左右浮動,致使前三行都有少量空白。第七個元素未浮動,因此從第一行開始填補每一行的空白區域。
- 第二個例子:第0個元素未浮動,第一到六個分別左右浮動。可以看到第一行的未浮動元素沒有向下填充下面行的空白,下面的浮動元素也沒有向上侵占未浮動元素的空間。
- 第三個例子:浮動元素長度增加了,第二個元素和第四個元素都超過了一行。但是第四個元素依然在空白處填補。
- 第四個例子:第三個例子未改動。但是使用鼠標選中了第一到第六個元素中間的部分文本。可以看到第7個元素雖然在中間穿插填補,但并未被選中。實際上選中順序還是按照HTML的順序,不是按照頁面上呈現的順序。
第一與第二個例子中六個浮動元素是一樣的,區別在于未浮動元素的位置。第一個例子在最后,元素向上填補了空缺。第二個例子在最前,元素沒有向下填補浮動元素造成的空缺。
浮動流中塊級元素與同高度行內元素
前面描述的行內元素都是同高度的場景,但行內元素和塊級元素都存在高度不同的場景。我們首先從簡單的塊級元素與同高度行內元素的組合場景開始看起。
僅塊級元素浮動
<html><body><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="brown block"></div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><div class="red block left"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="brown block"></div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><div class="red block left"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="brown block left"></div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="brown block left"></div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="brown block left"></div> <div class="maroon block left"></div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="brown block left"></div><div class="maroon block left"></div><div class="purple block"></div><span class="gray">第3個</span><span class="pink">第4個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.block {width: 100px;height: 40px;}</style>
</html>
這是一組較簡單的例子,沒有換行,所有塊級元素的高度一致而且都是左浮動。我們來分析一下:
- 第一個例子:塊級元素和行內元素間隔放置,沒有設置浮動,做對比用。可以看到塊級元素獨立一行,在塊級元素之間的行內元素們也是獨立一行。
- 第二個例子:紅塊級元素設置浮動。雖然浮動元素脫離了文檔流不占空間,但是沒有脫離“文本流”,行內元素還是會為它空出位置,因此行內元素在它同一行的后面顯示。至于棕色的塊級元素,沒有浮動,所以應該在上面行內元素的下一行展示。由于紅浮動元素并不占空間,因此和紅元素部分重疊展示。
- 第三個例子:兩個塊級元素同時浮動,到了一行。行內元素因此也在后面展示了。注意第二和第三個行內元素中間有空,這是因為它們中間原有一個塊級元素,雖然浮動走了,但是兩個行內元素并不緊挨,因此中間會出現空格。
- 第四個例子:棕塊級元素浮動。上面的紅元素繼續獨立一行,棕塊級元素則出現在了浮動元素之前。
- 第五個例子:在棕塊級元素浮動的基礎上,增加了浮動的褐塊級元素。可以看到橫向展示了。
- 第六個例子:在浮動的褐塊級元素的后面增加了一個非浮動的紫色塊級元素,可以看到如第二個例子一樣,紫色元素為上面的行內元素空出一行,然后與棕色元素部分重疊展示。最后的行內元素則獨立一行展示。
通過行內元素和塊級元素的對比,我們可知在前一個塊級元素浮動后,后面的非浮動塊級元素依然會獨立一行展示。但是后面的行內元素卻緊貼著浮動塊級元素同行展示。這也是浮動脫離文檔流但沒有脫離“文本流”的標志。
<html><body><div class="wrapper"><div class="red block"></div><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><div class="brown block"></div><span class="gray">第3個個個個個個個個個個個個個個個</span><span class="pink">第4個個個個個個個個個個個個個</span></div><div class="wrapper"><div class="red block left"></div><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><div class="brown block"></div><span class="gray">第3個個個個個個個個個個個個個個個</span><span class="pink">第4個個個個個個個個個個個個個</span></div><div class="wrapper"><div class="red block left"></div><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><div class="brown block left"></div><span class="gray">第3個個個個個個個個個個個個個個個</span><span class="pink">第4個個個個個個個個個個個個個</span></div><div class="wrapper"><div class="red block"></div><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><div class="brown block left higher"></div><div class="purple block left"></div><span class="gray">第3個個個個個個個個個個個個個個個個個個個個個個個</span><span class="pink">第4個個個個個個個個個個個個個個個個個個個個個</span></div><div class="wrapper"><div class="red block"></div><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><div class="brown block left"></div><div class="purple block left higher"></div><span class="gray">第3個個個個個個個個個個個個個個個個個個個個個個個</span><span class="pink">第4個個個個個個個個個個個個個個個個個個個個個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.block {width: 100px;height: 40px;}.higher {height: 100px;}</style>
</html>
這里又有幾個例子,主要展示了換行和塊級元素高度不同的場景。我們一個一個分析下:
- 第一個例子:塊級元素和行內元素間隔放置,沒有設置浮動,做對比用。可以看到行內元素正常換行。
- 第二個例子:紅塊級元素設置浮動。可以看到行內元素在紅元素右側展示,且因為紅元素可以容納兩行,因此在右側分行放置。行內元素的第三行因為空間不夠,獨立成行。
- 第三個例子:兩個塊級元素都設置了浮動。與上面行內元素沒有換行的場景不同,這次兩個元素分成兩行浮動了。這是因為浮動元素后面的塊級元素太長,導致第一個浮動元素后面沒有空間放置第二個浮動元素了,只能新起一行。
- 第四個例子:紅塊級元素沒有浮動。后面行內元素有三行,再后面的兩個塊級元素都設置了浮動。注意看行內元素的第三行,前面是兩個左浮動的塊級元素。因此,行內元素的最后一行后面如果有左浮動元素,該浮動元素會跑到這一行的最左邊。這與我們討論行內浮動元素時的規律一致。注意看兩個浮動元素的高度不一致,先高后矮。后面的行內元素,先在紫色的塊級元素后面一行一行展示,然后又在下面更高的棕色元素后一行一行展示。
- 第五個例子:與上一個例子不一樣的是,兩個浮動元素先矮后高。右側的浮動元素并沒有到棕色元素下面的空白區域展示,而是一直在右側浮動。這與我們前面看到的浮動塊級元素的規律類似。
僅行內元素浮動
<html><body><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="brown block"></div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><div class="red block"></div><span class="yellow left">第1個</span><span class="green">第2個</span><div class="brown block"></div><span class="gray">第3個</span><span class="pink left">第4個</span></div><div class="wrapper"><div class="red block"></div><span class="yellow left">第1個</span><span class="green">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="gray">第3個</span><span class="pink left">第4個</span><div class="brown block"></div></div><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green left">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="gray">第3個</span><span class="pink left">第4個</span><div class="brown block"></div></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.block {width: 100px;height: 40px;}</style>
</html>
- 第一個例子:塊級元素和行內元素間隔放置,沒有設置浮動,做對比用。
- 第二個例子:第一個和第四個文本左浮動。可以看到文本元素浮動僅在文本元素所在的行內部進行,不會影響塊級元素。
- 第三個例子:所有文本放在一起,且第二個文本超長,第一個和第四個文本左浮動。可以看到由于第二個元素跨行,所以第四個元素跑到文本第二行的最左邊。
- 第四個例子:第二個和第四個文本浮動。第二個文本由于超長因此獨立兩行展示,第四個文本沒有侵占第二個文本內的空間。注意我們沒有看到棕色塊級元素,因為它被浮動元素遮蓋了(注意看藍色邊框是留出棕色塊級元素位置的)。浮動元素由于脫離文檔流不占用空間,因此把下面的非浮動元素遮蓋了。
在這個場景下,規律與上面純行內元素的浮動場景一致,因此這里不過多討論了。另外注意“第四個例子”中,非浮動的文本元素會給浮動的塊級元素留出空間(即文本流),但是浮動的文本元素卻沒有給非浮動的塊級元素留出空間。關于這一點我們再看一下明確的對比:
<html><body><div class="wrapper"><div class="red block"></div><span class="yellow">第1個個個個個個個個個個</span></div><div class="wrapper"><div class="red block left"></div><span class="yellow">第1個個個個個個個個個個</span></div><div class="wrapper"><span class="yellow">第1個個個個個個個個個個</span><div class="red block"></div></div><div class="wrapper"><span class="yellow left">第1個個個個個個個個個個</span><div class="red block"></div></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.block {width: 100px;height: 40px;}</style>
</html>
- 第一個例子:塊級元素在上方,行內元素在下方,未浮動做對比用。
- 第二個例子:塊級元素浮動,下方的行內元素到了與塊級元素同行的位置,且給塊級元素留出了位置。
- 第三個例子:行內元素在上方,塊級元素在下方,未浮動做對比用。
- 第四個例子:行內元素浮動,下方的塊級元素位置上移。文本元素沒有給塊級元素留出位置,反而遮擋了下方的塊級元素。
塊級元素與行內元素同時浮動
<html><body><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="brown block"></div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><div class="red block left"></div><span class="yellow left">第1個</span><span class="green">第2個</span></div><div class="wrapper"><span class="yellow left">第1個</span><span class="green">第2個</span><div class="red block left"></div></div><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green left">第2個</span><div class="brown block left"></div><span class="gray">第3個</span><span class="pink left">第4個</span></div><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green left">第2個個個個個個個個個個個個個個個個個</span><div class="brown block left"></div><span class="gray">第3個</span><span class="pink left">第4個</span></div><div class="wrapper"><div class="red block"></div><span class="yellow">第1個</span><span class="green left">第2個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><div class="brown block left"></div><span class="gray">第3個</span><span class="pink left">第4個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.block {width: 100px;height: 40px;}</style>
</html>
- 第一個例子:未設置浮動,做對比用。
- 第二個例子:紅塊級元素與第一個文本元素設置了浮動,可以看到橫向順序排列。
- 第三個例子:紅塊級元素放到了最后,可以看到依然橫向排列,只不過位置發生了變化。
- 第四個例子:棕塊級元素,第二和第四個文本元素浮動。可以看到在第二排橫向展示,非浮動元素排列在后面。注意第三個文本元素因為和第一個元素的HTML中實際有個塊級元素,因此有個空隙。而第一個文本元素雖然和第四個元素的HTML中間也有塊級元素,但左側是浮動區域,因此不展示空隙了。
- 第五個例子:第二個文本元素長度加長。其它元素被擠到右邊,發生了換行。注意看此時雖然第四個文本元素浮動,一三文本元素未浮動,但是依然一三元素在上方,第四個元素在下方。
- 第六個例子:我們繼續加長第二個文本元素,使其超過一行。可以看到一三文本元素在第二行上方,第四個元素則跑到了最后。注意第二個文本元素在HTML中的位置是比第三個文本元素靠前,但是依然在后面展示。這與前面行內元素的展示邏輯是一樣的。
那么如果多個不同的塊級元素中間出現的“空白區域”,浮動或者浮動文本元素會不會補齊呢?我們看一下例子:
<html><body><div class="wrapper" style="margin-bottom: 50px"><div class="red block1 left"></div><div class="brown block2 left"></div><span class="yellow">第1個</span><span class="green">第2個</span><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><div class="red block1 left"></div><div class="brown block2 left"></div><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個</span><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 100px"><div class="red block1 left"></div><div class="brown block2 left"></div><span class="yellow left">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個</span><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><div class="red block1 left"></div><div class="brown block2 left"></div><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green left">第2個</span><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow left">第1個</span><div class="red block1 left"></div><div class="brown block2 left"></div><span class="green">第2個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 80px"><span class="yellow left">第1個</span><div class="red block1 left"></div><div class="brown block2 left"></div><span class="green left">第2個個個個個個個個</span><span class="gray left">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 100px"><span class="yellow left">第1個個個個個個個個個個</span><div class="red block1 left"></div><div class="brown block2 left"></div><span class="green left">第2個個個個個個個個</span><span class="gray left">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow left">第1個個個個個個個個個個</span><div class="red block1 left"></div><div class="brown block2 left"></div><span class="green left">第2個個個個個個個個</span><span class="gray left">第3個</span><span class="pink">第4個個個個個個個個個個個個個個個個個個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.block1 {width: 100px;height: 20px;}.block2 {width: 200px;height: 50px;}</style>
</html>
- 第一個例子:設置了兩個浮動的塊級元素,左邊低,右邊高,左邊下方留下的空白。這個例子主要做對比用。
- 第二個例子:第一個文本元素長度加長,使得其它文本元素跑到空白下面了,但是沒有去補齊空白。
- 第三個例子:第一個文本元素設置浮動,在下面單獨一行。可以看到其它文本元素在第一個文本元素上面展示了。
- 第四個例子:文本元素僅第二個設置了浮動,可以看到它位于當前行的最左位置,沒有向上補齊。
- 第五個例子:第一個文本元素改成了在塊級元素之前,第二個文本元素加長。可以看到依然沒有元素補齊空白。
- 第六個例子:在第五個例子的條件下,第二第三個文本元素浮動。可以看到第四個文本元素在右側上方展示。
- 第七個例子:第一個文本元素加長,導致兩個塊級元素不能在同一行。
- 第八個例子:第四個文本元素加長,可以看到依然沒有補齊空白。
因此,塊級浮動元素造成的左側空白是不能被補齊的,文本元素只能補齊右側的空白,而且是在非浮動狀態下。我們列舉幾個可以被補齊的例子:
<html><body><div class="wrapper" style="margin-bottom: 70px"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個</span><div class="red block2 left"></div><span class="green left">第2個</span><span class="gray left">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 50px"><div class="red block2 left"></div><div class="pink block2 left"></div><div class="purple block2 left"></div><span class="yellow">第1個個</span><span class="green">第2個個個個個</span><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 50px"><div class="red block2 left"></div><div class="pink block2 left"></div><div class="purple block2 left"></div><span class="yellow left">第1個個</span><span class="green">第2個個個個個</span><span class="gray">第3個</span><span class="pink">第4個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.block1 {width: 100px;height: 20px;}.block2 {width: 200px;height: 50px;}</style>
</html>
- 第一個例子:第一個文本元素與塊級元素在兩行分別左浮動。第二第三個文本元素左浮動。可以看到第四個文本元素去第一行補齊第一個文本元素右側的空白,但是左浮動的文本元素卻沒有。
- 第二個例子:三個塊級元素左浮動。右側的空白由文本元素補齊了。
- 第三個例子:第一個文本元素左浮動。可以看到其它文本元素去補齊右側,但是浮動的文本元素沒有。
浮動流中不同高度行內元素
前面列舉的元素中,行內元素中文本高度都是相同的,因此一行一行順序排列。假設行內元素的文本高度不同,現象又會怎樣呢?我們可以通過控制字號來實現對文本高度的控制。
場景舉例
<html><body><div class="wrapper"><span class="yellow size14">第1個</span><span class="green size35">第2個</span><span class="gray size14">第3個</span><span class="pink size35">第4個</span></div><div class="wrapper"><span class="yellow size14 left">第1個</span><span class="green size35">第2個</span><span class="gray size14">第3個</span><span class="pink size35 left">第4個</span></div><div class="wrapper"><span class="yellow size14">第1個</span><span class="green size35">第2個</span><span class="gray size14">第3個</span><span class="pink size35">第4個</span><span class="brown size14">第5個個個個個個個個個個個個個個個個個個</span></div><div class="wrapper"><span class="yellow size14 left">第1個</span><span class="green size35">第2個</span><span class="gray size14">第3個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="pink size35 left">第4個</span></div><div class="wrapper"><span class="yellow size14 left">第1個</span><span class="green size35 left">第2個</span><span class="gray size14">第3個個個個個個個個個個個個個個個個個個個個個個個個個個個個</span><span class="pink size35 left">第4個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.size14 {font-size: 14;}.size35 {font-size: 35;}</style>
</html>
- 第一個例子:兩種不同高度的文本元素展示,未浮動做對比用。默認垂直對齊是baseline。
- 第二個例子:第一個第四個元素左浮動。看到左浮動的1號元素的“垂直對齊方式”改變了。但實際上并未改變,觀察vertical-align還是baseline。這是因為設置后變為了塊級元素,是自己跟自己對齊,因此垂直對齊無意義了。
- 第三個例子:最后增加了第五個元素,且長度超過一行,可以看到并沒有填充左邊的空白,而是把所有元素整體作為一行,它自己跨到第二行展示。
- 第四個例子:第三個元素加長,使其換行,可以看到第四個元素到了最左邊浮動。
- 第五個例子:一二四元素都浮動,只有第三個元素非浮動。可以看到非浮動元素在浮動元素右側換行,沒有把左浮動都作為一行處理。
右側換行規律
這里再列舉幾個右側換行的例子:
<html><body><div class="wrapper"><span class="yellow size14">第1個個個</span><span class="green size35">第2個個個個個個個</span><span class="gray size14">第3個個個個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="wrapper"><span class="yellow size14">第1個個個</span><span class="green size35 left">第2個個個個個個個</span><span class="gray size14">第3個個個個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="wrapper"><span class="yellow size14 left">第1個個個</span><span class="green size35">第2個個個個個個個</span><span class="gray size14">第3個個個個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="wrapper"><span class="yellow size14 left">第1個個個</span><span class="green size35 left">第2個個個個個個個</span><span class="gray size14">第3個個個個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="wrapper"><span class="yellow size14 left">第1個個個</span><span class="green size35 left">第2個個個個個個個</span><span class="gray size14">第3個</span><span class="pink size14">第4個個個個個個個個個個個個個</span></div><div class="wrapper"><span class="yellow size14 left">第1個個個</span><span class="green size35 left">第2個</span><span class="gray size35">第3個</span><span class="pink size14">第4個個個個個個個個個個個個個個個個個個個個個</span></div><div class="wrapper"><span class="yellow size14 left">第1個個個</span><span class="green size35 left">第2個</span><span class="gray size35 left">第3個</span><span class="pink size14">第4個個個個個個個個個個個個個個個個個個個個個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.size14 {font-size: 14;}.size35 {font-size: 35;}</style>
</html>
- 第一個例子:一三是矮元素,二是高元素,均未設置浮動,做對比用。
- 第二個例子:二元素浮動,一元素被擠到右邊。三元素在右側換行了。
- 第三個例子:一元素浮動,二元素未浮動。這時候三元素沒有在右邊換行,而是整體換行了。
- 第四個例子:一二元素均浮動,三元素在右側換行。
- 第五個例子:增加了第四個元素,且三元素變短,四元素在右側換行了。
- 第六個例子:三元素變高,這時候四元素沒有在右側換行,而是整體換行了。
- 第七個例子:三元素變為左浮動,四元素又在右側換行了。
從這些例子中,可以看出行內元素在右側換行的規律:右側換行的多個元素是一個整體,這個整體的左邊的元素超過右邊這個整體的行高,且是浮動元素。即假設這個換行元素左側是非浮動元素,也可以換行,只要把右側的非浮動行內元素作為整體來換行即可。但如果些非浮動元素第一行的行高(取每個元素最高值)達到或者超過左側浮動元素的行高,則不在右側換行,而是和浮動元素作為一個整體換行。
浮動流中的可替換元素與行內塊元素
元素介紹
可替換元素是一類特殊的HTML元素,它內容的展現效果是由內部內容控制的,比如iframe和img元素。
行內塊元素是同時具有行內元素和塊級元素部分特性的元素,比如input和button元素。可以通過設置display: inlin-block
來指定為行內塊元素。
可替換元素和行內元素類似,在默認情況下它們都像行內元素一樣,在同一行橫向展示。但是也與塊級元素類似,可以指定元素的寬高。其它特性在這里就不描述了。我們舉例看一下這兩種元素的展示效果:
<html><body><div>個個個個<img class="common" src="./1.jpg" />個個個個<button class="common">按鈕</button>個個個個<button class="common vertical-top">按鈕</button>個個個個<input class="common" />個個個個<div class="common yellow inline-block"></div>個個個個</div></body><style>.common {width: 100px;height: 100px;}.inline-block {display: inline-block;}.vertical-top {vertical-align: top;}</style>
</html>
上面的例子展示了在文本中的可替換元素與行內塊元素的表現。可以看到它們都是行內元素,但可以設置寬度與高度。同時它們在行中的縱向位置表現不一樣:
- 第一個圖片元素和最后一個手動設置inline-block的黃元素,默認和文字的底端對齊。
- 第二個按鈕和第四個input元素,因為其中有文字,所以和文字居中對齊。
- 第三個按鈕,我們手動設置了
vertical-align: top
,于是和行內元素的最高處對齊。
浮動表現
看完了默認表現,我們再看一下它們在浮動流中的表現。
<html><body><div class="wrapper" style="margin-bottom: 100px"><span class="yellow">第1個</span><span class="green">第2個</span><img class="common left" src="./1.jpg" /><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 100px"><span class="yellow">第1個個個個個個個個個</span><span class="green">第2個個個個個個個個個個</span><img class="common left" src="./1.jpg" /><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><img class="common" src="./1.jpg" /><span class="gray left">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 100px"><span class="yellow">第1個</span><span class="green">第2個</span><input class="common left" /><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 100px"><span class="yellow">第1個個個個個個個個個</span><span class="green">第2個個個個個個個個個個</span><input class="common left" /><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><input class="common" /><span class="gray left">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 100px"><span class="yellow">第1個</span><span class="green">第2個</span><div class="common yellow inline-block left"></div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper" style="margin-bottom: 100px"><span class="yellow">第1個個個個個個個個個</span><span class="green">第2個個個個個個個個個個</span><div class="common yellow inline-block left"></div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="common yellow inline-block"></div><span class="gray left">第3個</span><span class="pink">第4個</span></div></body><style>.common {width: 100px;height: 100px;}.inline-block {display: inline-block;}.vertical-top {vertical-align: top;}.wrapper {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
例子比較長,但是沒什么難點,可替換元素與行內塊元素就像一個大塊頭的行內元素,具體表現和前面的部分場景是類似的。
- 第一個例子:img元素浮動。
- 第二個例子:img元素浮動的基礎上,文本長度增加,右側出現換行。
- 第三個例子:img元素不浮動,單獨一個文本元素浮動,雖然看起來縱向位置差較多,但實際上是在一行的。
- 第四個例子:與第一個例子一樣,但浮動元素變成了input,表現一致。
- 第五個例子:與第二個例子一樣,但浮動元素變成了input,表現一致。
- 第六個例子:與第三個例子一樣,但元素變成了input,除了垂直對齊外表現一致。
- 第七個例子:與第一個例子一樣,但浮動元素變成了行內塊的div,表現一致。
- 第八個例子:與第二個例子一樣,但浮動元素變成了行內塊的div,表現一致。
- 第九個例子:與第三個例子一樣,但元素變成了行內塊的div,表現一致。
元素內部包含行內元素
塊級元素內部可以包含行內元素,一些行內塊元素內部也可以包含行內元素,那么包含行內元素時,浮動的表現又如何呢?
塊級元素包含行內元素
<html><body><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange">塊級元素1</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange left">塊級元素1</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個</span><div class="orange left">塊級元素1</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange left">塊級元素1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</div><span class="gray">第3個</span><span class="pink">第4個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
我們在一個div內部放置了行內元素,沒有給這個div設置寬高。
- 第一個例子:div元素未浮動,獨占一整行,且高度由文本內容撐開。
- 第二個例子:div元素設置浮動,元素實際寬高都由文本內容撐開。
- 第三個例子:行內元素超長,浮動的div被擠到第二行。
- 第四個例子:浮動的div超長,元素在第二行展示且獨占兩整行。
上面列舉的例子看起來很常規,和前面正常塊級元素的表現基本一致。下面我們試一下,當塊級元素設置寬高,但不足以容納其中內容時的表現。
<html><body><div class="wrapper"><div class="orange common">塊級元素1個個個個個個個個個</div></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange common">塊級元素1個個個個個個個個個</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange left common">塊級元素1個個個個個個個個個</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個</span><div class="orange left common">塊級元素1個個個個個個個個個</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange left common">塊級元素1個個個個個個個個個</div><span class="gray">第3個個個個個個個個個個個個個個個個個個個個個</span><span class="pink">第4個個個個個個個個個個個個個個個個個個個個個個個個個個</span></div></body><style>.common {width: 100px;height: 40px;}.wrapper {border: 1px dotted blue;margin-bottom: 80px;}</style>
</html>
- 第一個例子:單獨列舉了div元素的寬高不能容納內容的例子。橘黃色背景的為div實際占用空間,文本內容超出展示了。
- 第二個例子:將div元素放到行內元素中,可以看到后面的行內元素覆蓋了超出的塊級元素文本。
- 第三個例子:div元素設置浮動,超出的文本元素依舊。
- 第四個例子:前面的行內元素超長,浮動的div被擠到第二行。
- 第五個例子:后面的行內元素超長,可以看到依舊覆蓋了div中超出的文本元素。
行內塊元素包含行內元素
<html><body><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange inline-block">塊級元素1</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange left inline-block">塊級元素1</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個</span><div class="orange left inline-block">塊級元素1</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange left inline-block">塊級元素1個個個個個個個個個個個個個個個個個個個個個個個個個個個個個個</div><span class="gray">第3個</span><span class="pink">第4個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}.inline-block {display: inline-block;}</style>
</html>
可以看到,除了第一個未浮動的例子行內塊元素和文本元素一行之外,其它例子和塊級元素一摸一樣,因此這里不再贅述了。下面再來看一下設置寬高,但不足以容納其中內容時的表現。
<html><body><body><div class="wrapper"><div class="orange common">塊級元素1個個個個個個個個個</div></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange common">塊級元素1個個個個個個個個個</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange left common">塊級元素1個個個個個個個個個</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個個個個個個個個個個個個個個個個個個個個個個個</span><span class="green">第2個</span><div class="orange left common">塊級元素1個個個個個個個個個</div><span class="gray">第3個</span><span class="pink">第4個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange left common">塊級元素1個個個個個個個個個</div><span class="gray">第3個個個個個個個個個個個個個個個個個個個個個</span><span class="pink">第4個個個個個個個個個個個個個個個個個個個個個個個個個個</span></div><div class="wrapper"><span class="yellow">第1個</span><span class="green">第2個</span><div class="orange common vertical-top">塊級元素1個個個個個個個個個</div><span class="gray">第3個</span><span class="pink">第4個</span></div></body><style>.common {width: 100px;height: 40px;display: inline-block;}.wrapper {border: 1px dotted blue;margin-bottom: 80px;}</style>
</html>
這里只有第二個例子與上面塊級元素不一樣。雖然行內塊元素中的文本超過了寬高,但第二個例子(也只有這個例子)為其留出了位置。如果我們設置div元素vertical-align: top
,(看第六個例子),則超過的區域又沒有被父級包裹。猜測應該是垂直對齊通過作用于行內元素,影響了父元素的包裹區域大小。
clear屬性清除浮動
在CSS中還有個clear屬性,用于清除浮動,取值有:none、left、right、both,對應不清除,清除左邊,清除右邊,左右都清除。雖然看起來叫做“clear”、“清除浮動”,但實際上不能起到“清除”的作用,只能說是“避開”,而且應用于行內元素無效。
clear用于塊級元素
看一下clear屬性在塊級元素上的表現,也通過這些例子了解clear屬性的作用。首先看一下clear作用于浮動元素上的例子。
<html><body><body><div class="wrapper"><div class="orange common right"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="teal common left"></div><span class="gray">第3個</span><span class="pink">第4個</span><div class="purple common left"></div></div><div class="wrapper"><div class="orange common right"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="teal common left"></div><span class="gray">第3個</span><span class="pink">第4個</span><div class="purple common left clear-left"></div></div><div class="wrapper"><div class="orange common right"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="teal common left clear-left"></div><span class="gray">第3個</span><span class="pink">第4個</span><div class="purple common left"></div></div><div class="wrapper"><div class="orange common right"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="teal common left clear-right"></div><span class="gray">第3個</span><span class="pink">第4個</span><div class="purple common left"></div></div><div class="wrapper"><div class="orange common right"></div><span class="yellow">第1個</span><span class="green">第2個</span><div class="teal common left"></div><span class="gray">第3個</span><span class="pink">第4個</span><div class="purple common left clear-right"></div></div></body><style>.common {width: 100px;height: 40px;}.wrapper {border: 1px dotted blue;margin-bottom: 80px;}</style>
</html>
- 第一個例子:三個塊級元素,兩個左浮動,一個右浮動,未設置clear,做對比用。
- 第二個例子:紫元素clear:left,因為前面有一個左浮動元素,因此避開到第二行展示。
- 第三個例子:青元素clear:left,但是前面并沒有左浮動元素了,因此無變化。注意clear并不會清除自己身上的浮動,也并不會清除其它元素上的浮動。
- 第四個例子:青元素clear:right。它的前面有一個右浮動元素,因此避開到第二行展示。后面的左浮動元素跟著也到了第二行展示。
- 第五個例子:紫元素clear:right。它的前面有一個右浮動元素,因此避開到第二行展示。
從上面幾個例子可以看到,clear并不會清除自身的浮動屬性,也更不會影響和清除其它浮動元素的屬性。它僅僅是通過改變自身的位置,避開前面元素的浮動行,另起一行展示而已。
<html><body><body><div class="wrapper"><div class="red common left clear-right"></div><div class="yellow common left"></div><div class="green common left"></div><div class="blue common right"></div></div><div class="wrapper" style="margin-bottom: 120px"><div class="blue common right"></div><div class="red common left clear-right"></div><div class="yellow common left"></div><div class="green common left"></div></div><div class="wrapper"><div class="red common left"></div><div class="yellow common left clear-right"></div><div class="green common left"></div></div><div class="wrapper" style="margin-bottom: 120px"><div class="red common left"></div><div class="yellow common left clear-left"></div><div class="green common left"></div></div><div class="wrapper"><div class="red common left"></div><div class="yellow common left clear-both"></div><div class="green common left"></div></div></body><style>.common {width: 100px;height: 40px;}.wrapper {border: 1px dotted blue;margin-bottom: 80px;}</style>
</html>
- 第一個例子:三個元素左浮動,一個元素右浮動。第一個左浮動元素設置clear:right,但是并無效果。因為右浮動元素在HTML中的位置在后面,因此無法影響到。
- 第二個例子:右浮動元素在HTML中的位置提到前面,這時候左浮動元素設置clear:right,就有效果了。
- 第三個例子:只有三個左浮動元素,中間元素設置了clear:right,效果和未設置一樣。因為中間元素的HTML位置中的前面并沒有右浮動元素。
- 第四個例子:三個左浮動元素,中間元素設置了clear:left,第二個元素和它后面的浮動元素被移動到第二行展示。
- 第五個例子:中間元素設置了clear:both,相當于第三個和第四個例子的結合。
通過上面的例子,我們可以看到,clear只能判斷HTML中位置處于前面的元素是否有左右浮動。我們再看一下clear應用于非浮動元素的例子。
<html><body><body><div class="wrapper"><div class="red common left"></div><div class="yellow common left"></div><div class="green common left"></div><div class="blue commonHeight"></div></div><div class="wrapper"><div class="red common left"></div><div class="yellow common left"></div><div class="green common left"></div><div class="blue commonHeight clear-left"></div></div><div class="wrapper"><div class="red common left"></div><div class="yellow common left"></div><div class="green commonHeight left"></div><div class="blue commonHeight"></div></div><div class="wrapper"><div class="red common left"></div><div class="yellow common left"></div><div class="green commonHeight left"></div><div class="blue commonHeight clear-left"></div></div><div class="wrapper"><div class="red common left"></div><div class="yellow commonHeight left"></div><div class="green common left"></div><div class="blue commonHeight clear-left"></div></div><div class="wrapper"><div class="red common left"></div><div class="yellow commonHeight right"></div><div class="green common left"></div><div class="blue commonHeight clear-left"></div></div><div class="wrapper"><div class="red common left"></div><div class="yellow commonHeight right"></div><div class="green common left"></div><div class="blue commonHeight clear-right"></div></div></body><style>.common {width: 100px;height: 40px;}.commonHeight {width: 100px;height: 60px;}.wrapper {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
- 第一個例子:前三個元素左浮動,第四個更高的藍元素不浮動,因為前面浮動元素不占位置,因此重疊展示。
- 第二個例子:第四個更高的藍元素設置了clear:left,可以看到藍元素靠下展示,沒有和浮動元素重疊。
- 第三個例子:未設置clear,第三個浮動元素高度提高,做對比用。
- 第四個例子:第四個藍元素設置了clear:left,由于第三個浮動是高元素,因此藍元素也避開了這部分高度。
- 第五個例子:換到了第二個浮動元素是高元素,四個藍元素位置不變。
- 第六個例子:第二個浮動元素變為了右浮動。因為第四個藍元素是clear:left,因此沒有空出右浮動元素高的這部分區域。
- 第七個例子:第四個藍元素設置為clear:right,可以看到有空出右浮動元素高的這部分區域。
通過上面的例子可以看到,clear屬性也能作用于非浮動元素,而且效果類似,都使得被設置的元素避開前面的浮動元素。
clear用于行內元素
<html><body><body><div class="wrapper"><span class="red">第1個</span><span class="yellow right">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span><span class="pink left">第6個</span><span class="brown left">第7個</span></div><div class="wrapper"><span class="red">第1個</span><span class="yellow right">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span><span class="pink left clear-left">第6個</span><span class="brown left">第7個</span></div><div class="wrapper"><span class="red">第1個</span><span class="yellow right">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray">第5個</span><span class="pink left clear-right">第6個</span><span class="brown left">第7個</span></div><div class="wrapper"><span class="red">第1個</span><span class="yellow right">第2個</span><span class="green">第3個</span><span class="blue left">第4個</span><span class="gray clear-both">第5個</span><span class="pink left">第6個</span><span class="brown left">第7個</span></div></body><style>.wrapper {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
上面的例子展示了行內元素clear的場景,我們具體分析一下:
- 第一個例子:第四個第六個第七個元素左浮動,第二個元素右浮動,做對比用。
- 第二個例子:第六個元素設置了clear:left,因此避開到第二行展示。后面的左浮動第七個元素跟隨到了第二行。
- 第三個例子:第六個元素設置了clear:right,因此避開到第二行展示。后面的左浮動第七個元素跟隨到了第二行。
- 第四個例子:第五個非浮動元素設置了clear:both,現象與不設置一樣無變化。
從上面的例子可以看到,對于行內元素來說,對浮動元素設置clear有效,對非浮動元素設置無效。但這背后的原因是行內元素浮動后,display屬性變化,會變為塊級元素,因此設置有效。綜合來看,clear屬性對于行內元素的設置是無效的。
<html><body><body><div class="wrapper"><span class="red">第1個</span><button class="common left">按鈕1</button><span class="yellow">第2個</span><button class="common right">按鈕2</button><span class="green">第3個</span><button class="common left">按鈕3</button><span class="blue">第4個</span></div><div class="wrapper" style="margin-bottom: 100px"><span class="red">第1個</span><button class="common left">按鈕1</button><span class="yellow">第2個</span><button class="common right clear-left">按鈕2</button><span class="green">第3個</span><button class="common left">按鈕3</button><span class="blue">第4個</span></div><div class="wrapper"><span class="red">第1個</span><button class="common left">按鈕1</button><span class="yellow">第2個</span><button class="common right">按鈕2</button><span class="green">第3個</span><button class="common">按鈕3</button><span class="blue">第4個</span></div><div class="wrapper"><span class="red">第1個</span><button class="common left">按鈕1</button><span class="yellow">第2個</span><button class="common right">按鈕2</button><span class="green">第3個</span><button class="common clear-left">按鈕3</button><span class="blue">第4個</span></div><div class="wrapper"><span class="red">第1個</span><button class="common left">按鈕1</button><span class="yellow">第2個</span><button class="common right">按鈕2</button><span class="green">第3個</span><button class="common">按鈕3</button><span class="blue clear-left">第4個</span></div><div class="wrapper"><div class="common left pink"></div><span class="red">第1個</span><button class="common left">按鈕1</button><span class="yellow">第2個</span><button class="common clear-left">按鈕2</button><span class="green clear-left">第3個</span></div></body><style>.common {width: 80px;height: 40px;}.wrapper {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
這些例子展示了行內元素,行內塊元素,塊級元素組合使用clear時的場景,可以發現行內元素與行內塊元素對于clear的規律是一致的:
- 第一個例子:三個按鈕,兩個左浮動,一個右浮動,作對比用。
- 第二個例子:按鈕2設置clear:left,按鈕2和3避開到第二行展示。
- 第三個例子:按鈕1和2設置浮動,按鈕3未設置浮動,做對比用。
- 第四個例子:按鈕3未浮動,設置clear:left,沒有效果。
- 第五個例子:文本4未浮動,設置clear:left,沒有效果。
- 第六個例子:最前面增加了一個左浮動塊級元素,按鈕2和文本3均未浮動,設置clear:left,沒有效果。
浮動的父元素塌陷與解決方案
問題描述
由于浮動元素不占空間,父元素可能無法把其中的浮動元素完全包裹在內。這時候浮動元素會覆蓋后面其它元素的展示,這種特點會對我們造成困擾。這些解決父元素塌陷問題的方法,被叫做clearfix。
<html><body><body><div class="wrapper"><img src="./1.jpg" class="common left"><span>第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。</span></div><div class="wrapper"><div class="common2 red"></div>第二段文字。第二段文字。第二段文字。第二段文字。第二段文字。第二段文字。第二段文字。第二段文字。</div></body><style>.common {width: 100px;height: 100px;}.common2 {width: 120px;height: 20px;}.wrapper {border: 1px dotted blue;}</style>
</html>
在上面的例子中,第一段有一個浮動的大圖片,它的高度超過了第一段的父元素的高度,侵占了第二段的部分空間,把第二段中紅色div的大部分區域都擋住了。這就是浮動的父元素塌陷問題。
下面會介紹很多種父元素塌陷問題的解決方案,這些解決方案不僅能應用到父元素,也能應用到后面被覆蓋的元素上解決問題。
方法:父元素設置固定高度
最簡單的方法就是給父元素設置一個固定的高度,或者固定的底部padding,margin等高度,即可以包裹進浮動元素。
<html><body><body><div class="wrapper" style="height: 120px"><img src="./1.jpg" class="common left"><span>第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。</span></div><div class="wrapper"><div class="common2 red"></div></div></body><style>.common {width: 100px;height: 100px;}.common2 {width: 120px;height: 20px;}.wrapper {border: 1px dotted blue;}</style>
</html>
在上面的例子中,我們給父級div設置了固定高度,下面的內容就可以露出來了。但這種方法太死板,不能根據浮動內容的高度自適應。
方法:clear和空塊級元素
前面我們聊過,使用css中的clear屬性,可以讓塊級元素避開浮動元素,在后面新起一行展示。利用這個特性,可以做到自適應浮動內容的高度。
<html><body><body><div class="wrapper"><img src="./1.jpg" class="common left"><span>第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。</span><div class="clear-both"></div></div><div class="wrapper"><div class="common2 red"></div></div></body><style>.common {width: 100px;height: 100px;}.common2 {width: 120px;height: 20px;}.wrapper {border: 1px dotted blue;}</style>
</html>
在父元素的最后,添加一個空的塊級元素,設置clear,即可讓父元素的區域包含這個空塊級元素以及上面的浮動元素。由于空塊級元素并不在視覺上占空間,因此頁面展示中看不出它的存在。
方法:clear和after偽類
有些人會覺得在html中增加空元素不太美觀,這時候還可以使用after偽類來代替空塊級元素。
<html><body><body><div class="wrapper after"><img src="./1.jpg" class="common left"><span>第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。</span></div><div class="wrapper"><div class="common2 red"></div></div></body><style>.after::after {content: "";display: block;clear: both;}.common {width: 100px;height: 100px;}.common2 {width: 120px;height: 20px;}.wrapper {border: 1px dotted blue;}</style>
</html>
使用after偽類在父元素的最后添加一個空元素,設置為塊級且clear,這時候就能起到和html中設置空塊級元素一樣的效果了。
方法:使用BFC(overflow)
區塊格式化上下文(Block Formatting Context,BFC)是一個以特定方式渲染的區域,在這里我們并不詳細介紹BFC的特點,但是BFC可以包含內部浮動與排除外部浮動,解決浮動的父元素塌陷問題。
很多種方式可以創建一個BFC,這里我們以比較常用的overflow為例。
<html><body><body><div class="wrapper overflow"><img src="./1.jpg" class="common left"><span>第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。</span></div><div class="wrapper"><div class="common2 red"></div></div></body><style>.overflow {overflow: auto;}.common {width: 100px;height: 100px;}.common2 {width: 120px;height: 20px;}.wrapper {border: 1px dotted blue;}</style>
</html>
可以看到,設置overflow這個看起來不相關的屬性之后,形成了一個BFC區塊,區塊中包含了所有浮動元素。
方法:使用BFC(flow-root)
使用overflow雖然好用,但是強制指定了overflow屬性。有沒有無副作用創建BFC的方式呢?那就是flow-root。設置display:flow-root可以創建一個BFC區塊。通過下面的例子可以看到,效果和overflow一樣。
<html><body><body><div class="wrapper flowroot"><img src="./1.jpg" class="common left"><span>第一段文字。第一段文字。第一段文字。第一段文字。第一段文字。</span></div><div class="wrapper"><div class="common2 red"></div></div></body><style>.flowroot {display: flow-root;}.common {width: 100px;height: 100px;}.common2 {width: 120px;height: 20px;}.wrapper {border: 1px dotted blue;}</style>
</html>
定位流
所謂定位流實際上就是CSS中的position屬性。position定位屬性在CSS中被經常使用,但定位流這個概念并不常見,一般只有在與浮動做對比的時候才提到。定位是針對于單個元素的,且方式有很多種,因此用一種“定位流”來描述我感覺并不準確。常用的定位方式有如下幾種:
- 靜態定位 static
- 相對定位 relative
- 絕對定位 absolute
- 固定定位 fixed
- 粘性定位 sticky
除了靜態定位外,與定位屬性結合的還有top, bottom, left, right屬性,分別設置距離上方,下方,左方,右方的偏移。下面分別簡單介紹這幾種定位方式。
靜態定位 static
靜態定位即正常的布局模式,遵守正常的文檔流規則,也是position屬性的默認值。由于無變化,這里就不提供例子了。
相對定位 relative
相對定位模式下,元素先按照正常的文檔流規則定位。然后再根據偏移屬性移動元素。移動后,原位置的空白依然被保留。
<html><body><body><div class="wrapper"><div class="common red"></div><div class="common yellow"></div><div class="common green"></div></div><div class="wrapper"><div class="common red"></div><div class="common yellow relative"></div><div class="common green"></div></div></body><style>.common {width: 100px;height: 100px;display: inline-block;}.relative {position: relative;top: 10px;left: 20px;}.wrapper {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
有兩個例子,第一個例子沒有設置定位,做對比用。第二個例子設置了相對定位,可以看到向右和向下偏移了部分位置,但偏移前的空白依然是保留的。
絕對定位 absolute
絕對定位是基于已定位的父級元素(非static)來進行定位的。定位元素會被移出文檔流,偏移量是根據已定位的父級元素位置來偏移。
<html><body><body><div class="wrapper"><div class="common red"></div><div class="common yellow"></div><div class="common green"></div></div><div class="wrapper" style="position:relative"><div class="common red"></div><div class="common yellow absolute"></div><div class="common green"></div></div></body><style>.common {width: 100px;height: 100px;display: inline-block;}.absolute {position: absolute;top: 10px;left: 20px;}.wrapper {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
第一個例子依然沒有設置定位,做對比用。第二個例子看到黃色元素原來的空位沒有了,偏移定位也是基于父級元素位置。
固定定位 fixed
固定定位的元素也會被移出文檔流,但定位偏移是根據屏幕視口的位置來偏移。
<html><body><body><div class="wrapper"><div class="common red"></div><div class="common yellow"></div><div class="common green"></div></div><div class="wrapper"><div class="common red"></div><div class="common yellow fixed"></div><div class="common green"></div></div></body><style>.common {width: 100px;height: 100px;display: inline-block;}.fixed {position: fixed;top: 100px;left: 200px;}.wrapper {border: 1px dotted blue;margin-bottom: 40px;}</style>
</html>
與absolute一樣,沒有留出空位置,但是偏移基于的位置變化了。注意fix是根據屏幕的位置來偏移的,拖動滾動條時的效果為:固定定位的元素位置不動,下面其它正常元素隨著滾動條位置移動。例如對上面的例子向下拖動的效果:
粘性定位 sticky
網上大部分關于粘性定位的說明是:相對定位和固定定位的結合。在達到偏移的位置前為相對定位,達到后則為固定定位。但是據我測試,達到偏移的位置前與相對定位不完全一樣,到偏移的位置后與固定定位也并不完全一樣。我們具體來看下:
<html><body><body><div class="wrapper"><div class="common red"></div><div class="common yellow"></div><div class="common green"></div></div><div class="wrapper"><div class="common red relative"></div><div class="common yellow"></div><div class="common green"></div></div><div class="wrapper"><div class="common red fixed"></div><div class="common yellow"></div><div class="common green"></div></div><div class="wrapper"><div class="common red sticky"></div><div class="common yellow"></div><div class="common green"></div></div><div class="wrapper"><div class="common red sticky"></div></div><div class="wrapper"><div class="gray" style="width: 100px; height: 10px"></div><div class="common red sticky"></div><div class="common yellow"></div><div class="common green"></div></div><div class="wrapper" style="position: relative; top: 15px"><div class="common red sticky"></div><div class="common yellow"></div><div class="common green"></div></div><div class="wrapper"><div class="common gray"></div><div class="common red sticky"></div><div class="common yellow"></div><div class="common green"></div></div></body><style>.common {width: 100px;height: 100px;}.wrapper {border: 1px dotted blue;width: 130px;float: left;}.relative {position: relative;top: 30px;}.fixed {position: fixed;top: 30px;}.sticky {position: sticky;top: 30px;}</style>
</html>
粘性定位相對比較復雜,因此提供了8個例子。首先注意到第一個圖,最上面有一條橫線,那是瀏覽器窗口的頂部。默認body會有8px的margin,因此所有的父級元素都是不到頂部的。這里不同例子中,偏移量都是top:30px。
第一張圖是默認最頂部無滾動條的場景,第二張圖是滾動了一部分,第三張圖是滾動更多。下面我們對每個例子進行分析。
- 第一個例子:紅黃綠三個元素縱向排列,沒有設置定位,做對比用。
- 第二個例子:紅元素設置了相對定位。可以看到紅元素位置下移,其他元素未動。紅元素偏移是相對于原有的自身位置,在這里是父元素的頂部(藍線)。
- 第三個例子:紅元素設置了固定定位。可以看到紅元素位置下移,其他元素上移,沒有給紅元素留出空間。另外固定定位的偏移相對于視口,因此偏移后會比第二個例子的位置更高一些。滾動條向下拖動時,紅元素保持屏幕視口的偏移位置不動。
- 第四個例子:紅元素設置了粘性定位。紅元素的下移位置并不像相對定位那樣基于父元素下移,而是類似與固定定位那樣根據視口的位置下移。滾動條向下拖動時,紅元素保持屏幕視口的偏移位置不動。
- 第五個例子:只有一個粘性定位的紅元素。可以看到位置并沒有偏移;向下滾動時紅元素也沒有動,與屏幕視口的位置無關。
- 第六個例子:粘性定位的紅元素上面增加了一個小小的div元素,它沒有影響紅元素的定位位置和屏幕視口的偏移位置。
- 第七個例子:父元素下移了10px,可以看到依舊沒有影響粘性定位的紅元素。
- 第八個例子:紅元素上方放置了灰元素,高度超過了原有紅元素默認情況下的偏移量。可以看到紅元素并沒有保持默認情況的偏移位置,而是被灰元素擠到下面去了。當滾動條向下拖動到了紅元素的偏移位置,此時紅元素就固定在屏幕視口的偏移位置了。
從上面這些例子,可以看到粘性定位與相對定位和固定定位都不完全一致,不能直接等同。這里描述一下特點:
- 粘性定位受限于父組件的位置,不管達到偏移前后,是相對還是固定模式,都不能超過父組件容器。如果超過則沒有“粘性”的效果了。
- 達到偏移前,元素類似于“靜態定位”,或者說是偏移位置不生效的“相對定位”。
- 滾動達到偏移時,類似固定定位,元素固定在屏幕視口的偏移位置。
- 初始位置在偏移后時,類似固定定位,元素初始在屏幕視口偏移的位置。當滾動時,元素也固定在屏幕視口的偏移位置。
注意例子里面的達到偏移前,代表的是第八個例子;初始位置在偏移后,代表的是第四個例子。關于粘性定位這里只是簡單描述,粘性定位還有其它一些特點,這里就略過了。
不同定位模式與文本流
這里我們看一下不同定位模式對文本流的影響。為啥不試一下定位模式對文檔流的影響呢?這是因為上面介紹各種定位模式時,實際上就是在文檔流中演示的,因此不用單獨介紹了。
<html><body><body><div class="wrapper"><div class="common red "></div><span class="green">我是行內元素。我是行內元素。我是行內元素。我是行內元素。我是行內元素。</span><div class="common yellow"></div></div><div class="wrapper"><div class="common red relative"></div><span class="green">我是行內元素。我是行內元素。我是行內元素。我是行內元素。我是行內元素。</span><div class="common yellow"></div></div><div class="wrapper" style="position: relative"><div class="common red absolute"></div><span class="green">我是行內元素。我是行內元素。我是行內元素。我是行內元素。我是行內元素。</span><div class="common yellow"></div></div><div class="wrapper"><div class="common red fixed"></div><span class="green">我是行內元素。我是行內元素。我是行內元素。我是行內元素。我是行內元素。</span><div class="common yellow"></div></div><div class="wrapper"><div class="common red sticky"></div><span class="green">我是行內元素。我是行內元素。我是行內元素。我是行內元素。我是行內元素。</span><div class="common yellow"></div></div><div class="wrapper"><div class="common yellow"></div><div class="common red sticky"></div><span class="green">我是行內元素。我是行內元素。我是行內元素。我是行內元素。我是行內元素。</span></div></body><style>.common {width: 100px;height: 100px;}.wrapper {border: 1px dotted blue;width: 150px;float: left;}.static {position: static;top: 30px;}.relative {position: relative;top: 30px;}.absolute {position: absolute;top: 30px;}.fixed {position: fixed;top: 30px;}.sticky {position: sticky;top: 30px;}</style>
</html>
上面列舉了每個定位模式,并且下面放置了文本元素,我們一個一個分析哪些模式會脫離文本流,即文本不會為定位的紅元素留出空間。
- 第一個例子:靜態定位,相當于未設置定位,當然未脫離文本流。
- 第二個例子:相對定位,文本流為偏移前的元素位置留出空間,這和文檔流一致。
- 第三個例子:絕對定位,已脫離文本流。
- 第四個例子:固定定位,已脫離文本流。
- 第五個例子:粘性定位,且初始位置在偏移后。類似于相對定位,文本流為偏移前的元素位置留出空間。向下滾動時文本流依然為偏移前的元素位置留出空間,和文檔流一致。
- 第六個例子:粘性定位,且初始位置在偏移前。類似于未設置定位,未脫離文本流。
總結
這篇文檔討論了文檔流,文本流,浮動流,定位流以及它們之間的關系。其中浮動流花的時間最長,討論也最細致。這也是我一開始的目的,就是想通過這個主題認真了解下浮動。通過了解我覺得浮動是比較復雜的CSS特性,即使我熟悉了排列方式,對于復雜場景如果不實際實驗,還是較難猜測出展示效果。不過浮動流的應用場景現在并不太多,至少我平時開發中不太常用。
參考
- MDN 介紹CSS布局
https://developer.mozilla.org/zh-CN/docs/Learn_web_development/Core/CSS_layout/Introduction - MDN 浮動
https://developer.mozilla.org/zh-CN/docs/Learn_web_development/Core/CSS_layout/Floats - HTML的文檔流和文本流分別是什么?
https://www.zhihu.com/question/21911352 - 文檔流、文本流、定位流、浮動流、脫離文檔流
https://blog.csdn.net/a18792627168/article/details/106298596 - HTML中的文檔流和文本流
https://juejin.cn/post/6844904013360545800 - css脫離文檔流到底是什么意思,脫離文檔流就不占據空間了嗎?脫離文檔流是不是指該元素從dom樹中脫離?
https://www.zhihu.com/question/24529373 - 文檔流和文本流的區別
https://www.cnblogs.com/gvip-cyl/p/6258119.html - CSS2 normal-flow
https://www.w3.org/TR/CSS2/visuren.html#normal-flow - MDN 常規流中的塊和內聯布局
https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_flow_layout/Block_and_inline_layout_in_normal_flow - MDN 塊級內容
https://developer.mozilla.org/zh-CN/docs/Glossary/Block-level_content - MDN 行級內容
https://developer.mozilla.org/zh-CN/docs/Glossary/Inline-level_content - MDN 區塊格式化上下文
https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_display/Block_formatting_context - MDN 行內格式化上下文
https://developer.mozilla.org/zh-CN/docs/Web/CSS/Inline_formatting_context - MDN float
https://developer.mozilla.org/zh-CN/docs/Web/CSS/float - 三個div都做浮動,給第二個div加上clear:both為什么右邊的還是在本行浮動?(clear:right無效)
https://www.zhihu.com/question/28166594 - 經驗分享:CSS浮動(float,clear)通俗講解
https://www.cnblogs.com/iyangyuan/archive/2013/03/27/2983813.html - 【CSS浮動屬性】別再糾結布局了!一文帶你玩轉CSS Float屬性
https://juejin.cn/post/7351321081562857522 - MDN 可替換元素
https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_images/Replaced_element_properties - MDN clear
https://developer.mozilla.org/zh-CN/docs/Web/CSS/clear - MDN 區塊格式化上下文 BFC
https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_display/Block_formatting_context - MDN position
https://developer.mozilla.org/zh-CN/docs/Web/CSS/position - position定位-sticky詳細講解
https://blog.csdn.net/qq_38382380/article/details/146250484