CSS Floats,浮動流的強大魔力

寫在前面

認識浮動元素已經好久了,可是最開始只用它來對齊文檔,最近整理筆記又複習到雙飛翼佈局和聖盃佈局。這兩種佈局的實現,偏偏也是藉助了浮動流的魔力。在筆記中搜索‘’float‘’或者‘’浮動‘’,能夠找到10個條目,結合着舊知識,今天再複習一波。css

什麼是浮動元素

CSS定義

浮動元素,正如其名,它「浮」在文檔表面,不佔據正常文檔流,咱們讓一個元素浮動很簡單,只要設置float屬性便可,可讓它浮動到父元素的最左邊或者最右邊。html

img {
  float: left;
}
複製代碼

浮動佈局的來源

浮動佈局最開始是用來實現雜誌上的圖片和文字混排,主要是文字圍繞圖片的效果。佈局

Flickr photo by presentday
在HTML5之前,還可使用<img align = 'right'>來實現這一功能

後來,Web開發者們發現使用float能夠浮動任何元素,不只僅是images,並且因爲浮動的特性,後一個浮動元素貼着前一個浮動元素(假設它們都向左浮動),因此浮動還能夠用來佈局,特別是多列布局。spa

如今隨着Flex佈局,以及一些其餘佈局技巧的出現,Float用來佈局只能算做是過期的技術,可是正是因爲它的魔力,咱們實現了不少難以想象的佈局。最爲出名的,仍是聖盃佈局和雙飛翼佈局了。3d

浮動元素不佔據文檔流,所以後面的元素會當它不存在,可是有如下幾點須要注意:code

1. 若是其兄弟元素是塊級元素,會當它不存在而覆蓋它orm

2. 若是是行內元素,則是會圍繞它cdn

3. 若是兄弟是塊級元素可是其內容是行內元素,那麼這些行內元素仍是會圍繞浮動元素htm

經典的三欄佈局問題

有一個經典的三欄佈局問題:左右邊欄寬度固定,中間欄寬度自適應,可是中間部份內容較爲重要,須要首先渲染(也就是先出如今DOM中),該如何實現?blog

若是單單提到三欄佈局,不限制三欄在DOM中順序的話,網上有不少方法,我記得比較深入的是下面兩種。

  1. 左右兩欄相對父元素container進行絕對定位,中間一欄設置左右margin分別等於邊欄寬度。這種作法中間一欄出如今DOM中的位置都OK
  2. 自身浮動佈局:左右兩邊分別向左和向右浮動,中間一欄出如今DOM最後面,因爲浮動元素脫離文檔流,中間欄設置好左右margin等於邊欄寬度便可
See the Pen 三欄佈局 - 絕對定位和自身浮動 by Tian Zhi ( @tianzhich) on CodePen.

固然,除了上面兩種,還可使用Flex佈局,以及接下來提到的聖盃佈局,雙飛翼佈局。

聖盃佈局

聖盃佈局來源於2006年發表在alistapart的一篇文章In Search of the Holy Grail。聖盃有西方「渴求之物」的意思,可能也是想說明這個佈局在當時的重要性。

聖盃佈局解決的是三欄佈局問題:左右邊欄寬度固定,中間欄寬度自適應,可是中間部份內容較爲重要,須要首先渲染(也就是先出如今DOM中)。

<div id="container">
  <div id="center" class="column"></div>
  <div id="left" class="column"></div>
  <div id="right" class="column"></div>
</div>
複製代碼

聖盃佈局採用的方法是讓父元素container使用padding爲左右兩邊預留出空間,而後中間佔比100%,三欄天然浮動,例如:

#container {
  padding: 0 200px;
}
#center {
  float: left;
  width: 100%;
  height: 400px;
  background-color: red;
}
#left {
  float: left;
  height: 200px;
  width: 200px;
  background-color: pink;
}
#right {
  float: left;
  height: 200px;
  background-color: blue;
  width: 200px;
}
複製代碼

效果圖以下:

‘’

此時咱們只須要讓左右兩邊分別上去,怎麼上去呢?正常流來講是上不去的(設置負的margin-left很大隻會讓它從左邊溢出文檔)。而浮動流,卻可讓它們上去。這裏咱們先看聖盃和雙飛翼的實現結果,浮動流的祕密最後再給出詳細解釋。

這裏咱們讓左邊欄margin-left: -100%,右邊欄margin-right: -200px(自身寬度)使它們的位置發生偏移

注意

  • 以前看到一些解釋都是左右兩邊都是相對佈局,其實否則,包括聖盃佈局那篇文章給出的也只是左邊使用了相對佈局,看上面的圖也能明白,右邊已經到了正確的位置
  • 若是右邊必定要使用相對佈局的話,則右邊欄是設置爲margin-left: -200px,而後相對佈局,向右位移200px,這裏設置margin-leftmargin-right在表現上有細微的不一樣,最後面給出了個人一些見解

最後設置左邊position: relative; right: 200px便可

再來看看雙飛翼。

雙飛翼佈局

雙飛翼佈局解決的問題和聖盃佈局同樣,都是三欄佈局,中間自適應,中間最早出如今DOM中,那爲什麼還要出現雙飛翼佈局。由於聖盃佈局會出現坍塌,所以聽說淘寶UED發明了雙飛翼佈局,從名字來看,雙飛翼比聖盃更能描述這種佈局。

聖盃佈局的坍塌

聖盃佈局在中間一欄寬度小於兩邊任意一欄時,會不起做用,仍是剛纔的例子,只不過把中間欄寬度縮小。

爲何會這樣,你可能會想,明明兩邊空白還足夠啊?這也和浮動流有關,若是着急瞭解,你能夠直接往下看。而這裏先知道聖盃佈局會失敗,所以纔有更好的雙飛翼佈局出現。

雙飛翼佈局的優點

雙飛翼佈局相對於聖盃佈局,再也不讓父元素給左右兩邊騰出位置,而中間一欄又不知道寬度。這樣其實中間一欄居中只能設置margin-left = margin-right爲左右兩欄寬度,可是因爲最終要把左右兩欄位移上來(只能經過浮動流),可是浮動流必須設置寬度(width或padding或border),不然將不存在。與中間欄不知道寬度形成矛盾。

雙飛翼佈局使用了一個trick,多用了一個div,在中間欄div下再使用一個div用來顯示content(這裏我再也不使用container,能夠認爲container就是body)。

<div class="main">
  <div class="main-content"></div>
</div>
<div class="left"></div>
<div class="right"></div>
複製代碼

這樣作能夠設定中間一欄的寬度爲100%,而真正的內容區域設置好左右margin給左右邊欄留出位置便可,而後讓外面這層父元素進行浮動。

.main {
  width: 100%;
  float: left;
}
.main-content {
  background-color: pink;
  margin: 0 200px;
  height: 300px;
}
.left {
  background-color: red;
  width: 200px;
  height: 150px;
  float: left;
}
.right {
  background-color: blue;
  width: 200px;
  height: 150px;
  float: left;
}
複製代碼

注意這裏和聖盃的不同,因爲左右欄的直接父元素爲body(沒有限制寬度),所以它們靠在了最左邊。

咱們讓左邊margin-left: -100%,右邊margin-left:-200px

直接一步到位並且不會坍塌。

最後給出對浮動流流動的我的看法,以及對上面兩個佈局給出詳細解釋。

浮動流究竟是如何流動的

浮動流的基本常識

咱們先看看MDN上對於浮動元素位置的基本解釋。

when an element is floated, it is taken out of the normal flow of the document (though still remaining part of it). It is shifted to the left, or right, until it touches the edge of its containing box, or another floated element.

意思就是一個元素若是設置爲浮動,會抽離文檔流,以float: left爲例,會向左移動,直到其碰到其父元素的左邊距或者是其他的浮動元素。

若是元素均向左浮動,浮動流從左向右。那麼,當一行空間不足會怎麼樣呢?看一個例子:

See the Pen 浮動流如何流 by Tian Zhi ( @tianzhich) on CodePen.

以上元素均向左浮動,第三個元素沒有空間了,此時它並不是直接另起一行,而是在第二個元素下方向左移動,直到遇到第一個浮動元素邊界。

基於這個原則,咱們能夠知道浮動元素若是換行,是基於它本來位置並向左移(假設float: left)。

左右邊欄是怎麼位移上去的

咱們先來看聖盃佈局和雙飛翼佈局中,左右邊欄未上去的狀況。

  • 雙飛翼佈局-左右邊欄在下一行

<div class="main">
  <div class="main-content"></div>
</div>
<div class="left"></div>
<div class="right"></div>
複製代碼

雙飛翼中父元素(body)寬度爲100%。左邊欄緊靠中間欄div.main-content外層容器div.main的右邊,見上圖。

因爲設置負的margin-left值,可讓元素迴流,100%則是相對於父元素的width而言的,所以雙飛翼佈局就很好解釋了。

  • 雙飛翼佈局-左右邊欄迴流上去

再來回過頭看聖盃佈局:

  • 聖盃佈局-左右邊欄在下一行

<div id="container">
  <div id="center" class="column"></div>
  <div id="left" class="column"></div>
  <div id="right" class="column"></div>
</div>
複製代碼

對於聖盃佈局,父元素div#container寬度即爲div#center寬度。左邊欄的位移和雙飛翼同樣,只不過上去以後再使用相對定位往左偏移。而對於右邊欄,位移上去使用的是負的margin-right,負的margin-right的做用是使文檔流後面的元素迴流,並且可能覆蓋它自身,因此在這裏換一種方式或許好理解一些。

以前提到父元素寬度不夠,因此左邊欄會換到下一行,設置負的margin-right,能夠用它抵消掉自身的width,在不考慮border的狀況下,若是所有抵消(盒子寬度爲0),就彷彿本身不存在。第一行天然能夠容納它,結果就會流回去。可是要記住,使用負的margin-left是使自身發生偏移,而負的margin-right抵消自身寬度,只是僞裝本身不存在,並不會發生位移,也就是說,哪怕margin-right絕對值再大,它也只能牢牢挨着前一個浮動元素邊界。

所以咱們直接讓右邊欄僞裝本身不存在從而移到上一行。

  • 聖盃佈局-左右邊欄迴流上去

聖盃佈局坍塌緣由

再來看看剛纔那張圖:

看完前面的解釋,這裏也不難理解爲何左右兩邊上不去了:

  1. 對於左邊欄,設置margin-left: -100%,並不能徹底抵消掉自身寬度,所以上不去
  2. 而對於右邊欄,設置margin-right爲負的自身寬度,即便抵消掉自身寬度,可是因爲它的浮動位置位於左邊欄以後,不能跨過左邊欄進行位移,因爲左邊欄上不去,所以,右邊欄也沒法上去

而雙飛翼則徹底沒有這個問題,由於父元素的width不受限,左右邊欄徹底只須要使用負的margin-left發生位移,移動到本身的位置上去便可。

總結

  1. 其實經過對這兩個佈局的深刻探討,已經能夠知道浮動流的祕密,特別是反向流動時的一些表現。
  2. 固然,本文沒有對負的margin值進行深刻研究。
  3. 其實弄懂了負margin和浮動流,不只能夠知道不少CSS trick,並且對於使用浮動元素的佈局也理解得更深(即便如今已經不常使用了)。

參考

  1. 本文的例子來自個人CodePen,都是一些簡單的代碼,須要能夠自行查看
  2. Float -- MDN
  3. CSS佈局中聖盃佈局與雙飛翼佈局的實現思路差別在哪裏?-- 知乎
  4. CSS佈局奇淫巧計之-強大的負邊距 -- 博客園(無雙)
  5. margin爲負值產生的影響和常見佈局應用 — 簡書(琦樂無窮)
相關文章
相關標籤/搜索