1. 程式人生 > >完全理解float之“不完全脫離文件流”

完全理解float之“不完全脫離文件流”

0.前言

  1. float的特性

  2. float與absolute的區別

  3. float與inline-block

  4. 清除浮動的方法及優缺點

1. float的特性

文字環繞

float 最早的設計目的是用於圖片,使文字能夠環繞在圖片周圍,像下面這樣:


文字環繞效果是很明顯的,這裡要注意一個地方:浮動的塊雖然脫離的正常的文件流,但是還會佔有正常文件流的文字空間,可以看到上面第二種圖,p的區域其實是頂到了img的底下的,因為float讓img脫離文件流,但是p上的文字卻沒有頂過去,也就是說p上的一部分文字空間仍然被img佔據著,所以從這裡也可以看出float的脫離文件流不是完全脫離。

包裹性

所謂的包裹性是指,使用float的元素會自動加上一個塊級框,也就是可以像塊級元素那樣設定寬高
,例子如下:




破壞性

float的破壞性主要是指它會使父容器的高度塌陷,也就是父元素在高度計算的時候會忽略浮動的元素


可以看到圖中名為taxian的元素高度為0。這個特性也正是它能夠實現文字環繞的原因,但是由於後來float被大量應用到頁面佈局之中,所以這個我們不得不想辦法清除浮動,這個在下文會有提到。

2. float和position:absolute

脫離文件流

雖然在我們常常看到描述float和absolute的時候,都陳偉脫離文件流,但是實際上並不完全相同:
在脫離文件流方面,absolut正如它的名字一般,是絕對脫離

,設定了該屬性的元素,將完全獨立在文件流之外,不會對其他的元素產生任何影響,就舉上面文字環繞的例子來說,如果把img屬性的float換成position:absolue屬性的話,那麼p元素以及上面的文字都會頂到圖片的位置上,就像這樣:


而對於float我們之前已經提出,float只是脫離了文件流的dom空間但是還佔據著文字空間(這兩個名詞不知道是否已經有更標準的詞語出現,在這裡只是個人用法,見諒)

高度塌陷

float和absolute都能引起父元素的高度塌陷,同樣地,由於absolute是完全脫離文件流,所以這種情況的高度塌陷是沒辦法清除的;float引起的高度塌陷則是可清除的,我們常說的清除浮動

就是指清除float帶來的高度塌陷問題,在下文會有提到。

在兩列布局中的使用

float和absolute都被廣泛用於兩列布局之中,absolute由於完全脫離,可以做到精準的定位,但是不利於設計兩列之間的聯動變化;float屬性可以保留一些相互影響,但是要非常小心傳遞來的問題,比如clear的不當使用會導致左右佈局異常聯動,在後面講清除浮動時會專門講解。而且在使用浮動佈局的時候,要注意某些情況下要交換浮動左右浮動元素的宣告次序

3. float和display:inline-block

橫向排列

首先,使用floatinline-block都能使li橫向排列。但是,使用float可以選擇排列的方向,而inline只有一種方向;
第二是在單純排列圖片的時候,如果圖片大小不是完全一致的,那麼使用這兩個屬性都能完成比較合適的排列:


但是如果圖片大小不等高,float的脫離文件流特性導致排列的某些圖片會被擠到下一行,導致垂直方向無法對齊,如下:

而如果使用display:inline-block則可以保證垂直方向的對齊:

所以如果是要保證垂直對齊的情況下,使用display:inline-block會比較合適

float和displayinline-block這兩個屬性有一個很經常用到的地方就是橫向導航。導航中一般是單行對齊,而且除了圖片之外還有文字,這時候如果採用display:inline-block, 必須要考慮display:inline-block屬性帶來的空白間隙問題(這個問題可以自行查詢,本文中不贅述),此時使用float:left更為合適一些。

4.關於清除浮動

清除浮動的方式

前文中提到float屬性會引起父容器高度塌陷的問題,因此我們需要清除浮動。

在閱讀這塊內容之前,請先了解css中的BFC(這個問題可以自行查詢,本文中不贅述),在此基礎上,我認為清除浮動,根據原理來劃分,分為兩類:

  1. 利用clear屬性清除浮動

  2. 利用bfc原理包容浮動

首先介紹第一類,利用clear原理清除浮動,如果大家有過經驗都知道,通常利用clear屬性清除浮動的方式有兩種:

  • 利用新增空標籤清除浮動

  • 通過after偽類清除元素

這兩種方式只是寫法上有所不同,通過偽類清除可以讓程式碼比較簡潔,並且符合語義化的原則(其實就是可以少寫無意義的空標籤)現在比較流行的bootstrap框架或者其他各大框架中,通常使用一下程式碼來清除:

.clearfix:before,
.clearfix:after
{
  display: table;
  content: " ";
}
.clearfix:after
{
  clear: both;
}
.clearfix{zoom:1;} //ie 6 7

其實這裡起清除浮動的作用的是隻是
.clearfix:after
 {
    content: " ";
    clear: both;
 }

至於before和after中的display:table;是為了防止子元素垂直方向上的邊距摺疊,也就是通常說的子元素margin-top會被轉移到父元素的問題(為防止篇幅過長這個問題也不在此解釋,如果有需要可以私信回答)。

所以以上的效果就相當於在父元素最後插入一個子元素,並且設定clear:both屬性,這是現在最通用的辦法,但是其實並無是完美無缺的

clear使用不當的例子

(這裡為什麼用了大號呢,因為這個問題很重要!很重要!很重要!)

舉一個之前專案中碰到的一種情況,為了方便大家理解,在這裡把模型簡化,程式碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>float</title>
    <style>
        *{
            padding: 0;
            margin:0;
        }
        .div1{
            float: left;
            width: 100px;
            height: 100px;
            background-color: lightpink;
        }
        .div2{
            margin-left:100px;
            background-color: lightgreen;
        }
    </style>
</head>
<body>
        <div class="div1">
        這是div1
        </div>
        <div class="div2">
            <div style="float:left">這是一個浮動的標題</div>
            <div style="clear:both"></div>
        </div>
</body>
</html>
這段程式碼是一個非常簡單的左右兩列布局,在右邊內部有個浮動的標題,於是在後面跟上一個清除浮動的子元素(這裡採用空標籤只是為了在研究問題的時候排除偽類元素的干擾),但是存在一個問題:右邊的div2會自動適應div1的高度,或者說清除浮動的容器會有高度,我們可以在f12中直接改變左邊div1的高度,可以看到右邊的高度也隨之改變。


這種情況有很多方法可以處理,比如讓div2形成一個bfc容器,但是很少看到有文章講到問題的根源,我查了很久,最後發現問題是源於clear這個屬性上設計:

clear:
This property indicates which sides of an element's box(es) may not be adjacent to an earlier floating box. The 'clear' property does not consider floats inside the element itself or in other block formatting contexts.

clear:both
Requires that the top border edge of the box be below the bottom outer edge of any right-floating and left-floating boxes that resulted from elements earlier in the source document

以上是w3c文件上關於clear和clear:both的描述,大概有以下兩個重點:

  • clear清除浮動對於其他形成bfc的塊內部的浮動元素是無效的

  • clear清除浮動的原理是:讓添加了clear屬性的那個元素的top邊緣在某側或者兩側(看設定的值是left right還是both)浮動元素的底邊距之下

其實這個很好理解,我們之所以能夠使用clear解決float引起的父元素塌陷問題,其實就是因為加了clear的空標籤或者是那麼偽類元素,把top值設定在了浮動元素的bottom邊緣下方,從而能夠撐起父元素。

所以最後我們就知道上面的問題出在哪裡了:clear是清除某側或者兩側的所有浮動,結合上面那個例子來看,其實是有兩處浮動的,第一是左側的div1,第二是在div2內部有個浮動的標題,我們的目的是要清除內部的浮動,但是因為clear本身的定義,就把兩個浮動都清除了,也就是把加了clear屬性的標籤top值設定了浮動元素的bottom邊緣下方,所以,那個塊將會和左側等高(實質應是設定了clear空標籤的高度為0並且top剛好在div的下方)。

總結

上面的一段說的有點拗口,不知道大家有沒有理解,不過可以拿例子去跑一下,應該就很容易理解了。
既然問題找到了,那相應的解決方案也就出來了:

  1. 左側使用absolute佈局避開這個問題

  2. 給右側div2添加overflow:auito形成bfc,從而隔離clear的作用範圍

現在回到清除浮動的問題主線,關於使用bfc包含浮動的情況,瞭解了bfc特點後我們就知道bfc的內部是會計算浮動元素的高度的,所以直接給浮動元素父元素加上overflow:auto或者其他可以構成bfc的屬性即可。