1. 程式人生 > >詳解 清除浮動 的多種方式(clearfix)

詳解 清除浮動 的多種方式(clearfix)

說明

本文適合知道HTML 與 CSS基礎知識的讀者,或者想要了解清除浮動背後原理的讀者!

1.什麼是浮動

首先我們需要知道定位
元素在頁面中的位置就是定位,解決問題之前我們先來了解下幾種定位方式
1、普通流定位 static(預設方式)
普通流定位,又稱為文件流定位,是頁面元素的預設定位方式
頁面中的塊級元素:按照從上到下的方式逐個排列
頁面中的行內元素:按照從左到右的方式逐個排列
但是如何讓多個塊級元素在一行內顯示?
這裡就引出了浮動定位
2、浮動定位 float
float屬性 取值為 left/right
這個屬性原本不是用來佈局的,而是用來做文字環繞的,但是後來人們發現做佈局也不錯,就一直這麼用了,甚至有些時候都忘了用他做文字環繞
3、相對定位 relative


元素會相對於它原來的位置偏移某個距離,改變元素位置後,元素原本的空間依然會被保留
語法
屬性:position
取值:relative
配合著 偏移屬性(top/right/bottom/left)實現位置的改變

4、絕對定位 absolute
如果元素被設定為絕對定位的話,將具備以下幾個特徵
1、脫離文件流-不佔據頁面空間
2、通過偏移屬性固定元素位置
3、相對於 最近的已定位的祖先元素實現位置固定
4、如果沒有已定位祖先元素,那麼就相對於最初的包含塊(body,html)去實現位置的固定
語法
屬性:position
取值:absolute
配合著 偏移屬性(top/right/bottom/left)實現位置的固定

5、固定定位 fixed
將元素固定在頁面的某個位置處,不會隨著滾動條而發生位置移動
語法
屬性:position
取值:fixed
配合著 偏移屬性(top/right/bottom/left)實現位置的固定

2.浮動的效果

  • 浮動 之後會怎麼樣?
    1、浮動定位元素會被排除在文件流之外-脫離文件流(不佔據頁面空間),其餘的元素要上前補位
    2、浮動元素會停靠在父元素的左邊或右邊,或停靠在其他已浮動元素的邊緣上(元素只能在當前所在行浮動)
    3、浮動元素依然位於父元素之內
    4、浮動元素處理的問題-解決多個塊級元素在一行內顯示的問題
    注意
    1、一行內,顯示不下所有的已浮動元素時,最後一個將換行
    2、元素一旦浮動起來之後,那麼寬度將變成自適應(寬度由內容決定)
    3、元素一旦浮動起來之後,那麼就將變成塊級元素,尤其對行內元素,影響最大
    塊級元素:允許修改尺寸
    行內元素:不允許修改尺寸
    4、文字,行內元素,行內塊元素時採用環繞的方式來排列的,是不會被浮動元素壓在底下的,會巧妙的避開浮動元素
  • 浮動 之後會有什麼樣的影響?
    由於浮動元素會脫離文件流,所以導致不佔據頁面空間,所以會對父元素高度帶來一定影響。如果一個元素中包含的元素全部是浮動元素,那麼該元素高度將變成0(高度塌陷)

3.如何清除浮動

解決方案 及 原理分析

方案1

直接設定父元素的高度
優勢:極其簡單
弊端:必須要知道父元素高度是多少

方案2

在父元素中,追加空子元素,並設定其clear屬性為both
clear是css中專用於清除浮動的屬性
作用:清除當前元素前面的元素浮動所帶來的影響
取值:
1、none
預設值,不做任何清除浮動的操作
2、left
清除前面元素左浮動帶來的影響
3、right
清除前面元素右浮動帶來的影響
4、both
清除前面元素所有浮動帶來的影響
優勢:程式碼量少 容易掌握 簡單易懂
弊端:會新增許多無意義的空標籤,有違結構與表現的分離,不便於後期的維護

方案3

設定父元素浮動
優勢:簡單,程式碼量少,沒有結構和語義化問題
弊端:對後續元素會有影響

方案4

為父元素設定overflow屬性
取值:hidden 或 auto
優勢:簡單,程式碼量少
弊端:如果有內容要溢位顯示(彈出選單),也會被一同隱藏

方案5

父元素設定display:table
優勢:不影響結構與表現的分離,語義化正確,程式碼量少
弊端:盒模型屬性已經改變,會造成其他問題

方案6

使用內容生成的方式清除浮動

.clearfix:after {
   content:""; 
   display: block; 
   clear:both; 
}

:after 選擇器向選定的元素之後插入內容
content:""; 生成內容為空
display: block; 生成的元素以塊級元素顯示,
clear:both; 清除前面元素浮動帶來的影響
相對於空標籤閉合浮動的方法
優勢:不破壞文件結構,沒有副作用
弊端:程式碼量多

方案7
.cf:before,.cf:after {
   content:"";
   display:table;
}
.cf:after { clear:both; }

優勢:不破壞文件結構,沒有副作用
弊端: 程式碼量多
注意:display:table本身無法觸發BFC,但是它會產生匿名框(anonymous boxes),而匿名框中的display:table-cell可以觸發BFC,簡單說就是,觸發塊級格式化上下文的是匿名框,而不是display:table。所以通過display:table和display:table-cell建立的BFC效果是不一樣的(後面會說到BFC)。

CSS2.1 表格模型中的元素,可能不會全部包含在除HTML之外的文件語言中。這時,那些“丟失”的元素會被模擬出來,從而使得表格模型能夠正常工作。所有的表格元素將會自動在自身周圍生成所需的匿名table物件,使其符合table/inline-table、table-row、table- cell的三層巢狀關係。

疑問

為什麼會margin邊距重疊?
overflow:hidden, 語義應該是溢位:隱藏,按道理說,子元素浮動了,但依然是在父元素裡的,而父元素高度塌陷,高度為0了,子元素應該算是溢位了,為什麼沒有隱藏,反而撐開了父元素的高度?
為什麼display:table也能清除浮動,原理是什麼?

解釋

要解釋這些疑問,我們就要提到Formatting context
Formatting context是W3C CSS2.1規範中的一個概念。它是頁面中的一塊渲染區域,並且有一套渲染規則,它決定了其子元素將如何定位,以及和其他元素的關係和相互作用。
最常見的Formatting context有Block fomatting context(簡稱BFC)和Inline formatting context(簡稱IFC)。
CSS2.1 中只有BFC和IFC, CSS3中還增加了GFC和FFC
這裡主要說BFC
BFC(Block formatting context)直譯為”塊級格式化上下文”。它是一個獨立的渲染區域,只有Block-level box參與, 它規定了內部的Block-level Box如何佈局,並且與這個區域外部毫不相干。
block-level box,display屬性為block, list-item, table的元素,會生成block-level box。並且參與block fomatting context。
inline-level box, display屬性為inline, inline-block, inline-table的元素,會生成inline-level box。並且參與inline formatting context。

BFC佈局規則:
1、內部的Box會在垂直方向,按照從上到下的方式逐個排列。
2、Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊
3、每個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此。
4、BFC的區域不會與float box重疊。
5、BFC就是頁面上的一個隔離的獨立容器,容器裡面的子元素不會影響到外面的元素。反之也如此。
6、計算BFC的高度時,浮動元素的高度也參與計算

觸發BFC的條件
1、根元素
2、float 取值 none 以外的值
3、overflow 除了visible 以外的值(hidden,auto,scroll )
4、display (table-cell,table-caption,inline-block,flex,inline-flex)
5、position(absolute,fixed)

舉例詳解BFC

<style>
   .top{
    width:100px;
    height:100px;
    background:red;
    margin:50px;
   }
   .bottom{
    width:100px;
    height:100px;
    background:blue;
    margin:20px;
   }
</style>
<body>
    <div>
        <div class="top">上</div>
    </div>

    <div class="bottom">下</div>
</body>

BFC2
依據BFC佈局規則第二條:

Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊
注意:發生重疊後,外邊距的高度等於兩個發生重疊的外邊距的高度中的較大者

從上面的例子可以看出,雖然紅色 和 藍色 的 div 都有設定 margin ,但是最後兩個div 之間的距離並不是 50 + 20,而是取了較大者 50。

如何解決這個問題?
用開始提到的方案7 就可以了

<style>
   .top{
    width:100px;
    height:100px;
    background:red;
    margin:50px;
   }
   .bottom{
    width:100px;
    height:100px;
    background:blue;
    margin:20px;
   }
   .cf:before,.cf:after {
     content:"";
     display:table;
    }
   .cf:after { clear:both; }
</style>

<body>
    <div class="cf">
        <div class="top"></div>
    </div>

    <div class="bottom"></div>
</body>

這裡寫圖片描述

<style>
   .top{
    width:100px;
    height:100px;
    background:red;
    float:left;
   }
   .bottom{
    width:200px;
    height:200px;
    background:blue;
   }
</style>
<body>
    <div class="top"></div>
    <div class="bottom"></div>
</body>

BFC3
依據BFC佈局規則第三條:

每個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此。

我們可以看到,雖然有浮動的元素top,但是bottom的左邊依然與包含塊的左邊相接觸。

<style>
   .top{
    width:100px;
    height:100px;
    background:red;
    float:left;
   }
   .bottom{
    width:200px;
    height:200px;
    background:blue;
    overflow:hidden;   
   }
</style>
<body>
    <div class="top"></div>
    <div class="bottom"></div>
</body>

BFC4
依據BFC佈局規則第四條:

BFC的區域不會與float box重疊。

看程式碼和效果圖,可以看出,這次的程式碼比上面的程式碼多了一行overflow:hidden;用這行程式碼觸發新的BFC後,由於這個新的BFC不會與浮動的top重疊,所以bottom的位置改變了

<style>
   p{
    width:100px;
    height:100px;
    background:red;
    float:left;
   }
   div{
    width:200px;
    border:1px solid blue;
   }
</style>
<body>
    <div>
       <p></p>
    </div>
</body>

這裡寫圖片描述

當藍色 div 增加 overflow:hidden; 時 效果如下
這裡寫圖片描述
依據BFC佈局規則第六條:

計算BFC的高度時,浮動元素的高度也參與計算。

到此我們應該是解決了上面的所有疑問了。

總結

清除浮動的方式有很多種,但是實現的原理主要是靠clear屬性,和觸發新的BFC,通過詳細的解釋與比較,最後兩種內容生成的方式是比較推薦使用的,如果需要考慮margin重疊的問題,就用方案7,不考慮就用方案6,如果大家還有什麼巧妙的方式,可以留言,分享一下!