深入理解CSS定位—浮動模型

前面我們講到了絕對定位,在這篇文章中,我們將講到3種定位模型中的浮動模型。主要參考

注意:第二小節基本參考一絲絲涼的內容,看過這篇就可以略過我的那部分內容。

1. 浮動

浮動:浮動的框可以左右移動,直到它的外邊緣碰到包含框或另一個浮動框的邊緣。和絕對定位元素一樣,使用浮動後,該元素也會脫離文檔流,即浮動框不屬於文檔中的普通流當一個元素浮動之後,不會影響到塊級框的佈局而只會影響內聯框(通常是文本)的排列,文檔中的普通流就會表現得和浮動框不存在一樣,當浮動框高度超出包含框的時候,也就會出現包含框不會自動伸高來閉合浮動元素(“高度塌陷”現象)。顧名思義,就是漂浮於普通流之上,像浮雲一樣,但是隻能左右浮動。

正是因爲浮動的這種特性,導致本屬於普通流中的元素浮動之後,包含框內部由於不存在其他普通流元素了,也就表現出高度爲0(高度塌陷)。在實際佈局中,往往這並不是我們所希望的,所以需要閉合浮動元素,使其包含框表現出正常的高度。

1.1 浮動設計的初衷與特性

浮動設計的初衷是爲了實現文本環繞效果。明白了浮動的設計初衷,我們就能明白浮動的特性表現了。浮動具有以下兩個特性:

  • 包裹性
  • 破壞性

單純只是說浮動的特性:包裹性與破壞性,很多小夥伴可能會很迷糊,不知所云。那麼下面我們結合案例來說明以下,便於理解。

包裹性

什麼是包裹性呢?這個需要結合栗子理解。下面是一個普普通通的div小青年,給它加上背景色,可以看到,獨佔一行(塊級元素特性)。同樣的div,給它加上float:left,可以看到,框收縮了,緊緊包裹住它的內容。

body {
    margin: 0;
    padding:0;
}

.container {
    width: 800px;
    float: left;
    margin: 0 auto;

}

.normal {
    background-color: salmon;
}

.flo {
    float: left;
    background-color: seagreen;
}
  <div class="container">
       <div class="normal">普普通通的div小青年</div>
       <div class="flo">浮動小青年</div>
 </div>

具有包裹性的其它小夥伴:

  • display:inline-block/table-cell/...
  • position:absolute/fixed/sticky
  • overflow:hidden/scroll

破壞性

正如前文所說,“使用浮動後,元素會脫離文檔的普通流,它不會影響到塊級框的佈局而只會影響內聯框(通常是文本)的排列,文檔中的普通流就會表現得和浮動框不存在一樣,當浮動框高度超出包含框的時候,也就會出現包含框不會自動伸高來閉合浮動元素(“高度塌陷”現象)。“

栗子:

        <div class="container">
            <div class="flo">浮動小青年</div>
        </div>

正常情況(不給類flo加浮動):

給div加上浮動後,容器“高度塌陷”。

具有破壞性的其它小夥伴:

  • display:none
  • position:absolute/fixed/sticky

2. 清除浮動(更準確,閉合浮動)

由於浮動的特性,所以運用它來佈局時候我們通常需要清除浮動,更嚴謹的說,是閉合浮動:使浮動元素閉合,從而減少浮動的影響。

2.1 清除浮動的方法

清除浮動的各種方法:

(1)添加額外的標籤

​ 通過在浮動元素末尾添加一個空的標籤例如div元素附加clearLboth;css屬性,其他標籤br等亦可。

 <div class="wrap" id="float1">
	<h2>1)添加額外標籤</h2>
	<div class="main left">.main{float:left;}</div>
	<div class="side left">.side{float:right;}</div>
	<div style="clear:both;"></div>
</div>
<div class="footer">.footer</div>

優點:通俗易懂,容易掌握

缺點:可以想象通過此方法,會添加多少無意義的空標籤,有違結構與表現的分離,在後期維護中將是噩夢,這是堅決不能忍受的,建議不要使用。

(2)使用 br標籤和其自身的 html屬性

​ 這個方法有些小衆,br 有 clear=“all | left | right | none” 屬性

 <div class="wrap" id="float2">
	<h2>2)使用 br標籤和其自身的 html屬性</h2>
	<div class="main left">.main{float:left;}</div>
	<div class="side left">.side{float:right;}</div>
	<br clear="all" />
</div>
<div class="footer">.footer</div>

優點:比空標籤方式語義稍強,代碼量較少

缺點:同樣有違結構與表現的分離,不推薦使用

(3) 父元素設置 overflow:hidden;

​ 通過設置父元素overflow值設置爲hidden;在IE6中還需要觸發 hasLayout ,例如 zoom:1;

<div class="wrap" id="float3" style="overflow:hidden; *zoom:1;">
	<h2>3)父元素設置 overflow </h2>
	<div class="main left">.main{float:left;}</div>
	<div class="side left">.side{float:right;}</div>
</div>
<div class="footer">.footer</div>

優點:不存在結構和語義化問題,代碼量極少

缺點:內容增多時候容易造成不會自動換行導致內容被隱藏掉,無法顯示需要溢出的元素;04年POPO就發現overflow:hidden會導致中鍵失效,所以還是不要使用了.

(4) 父元素設置 overflow:auto 屬性

​ 同樣IE6需要觸發hasLayout,和3差不多

<div class="wrap" id="float3" style="overflow:auto; *zoom:1;">
	<h2>3)父元素設置 overflow </h2>
	<div class="main left">.main{float:left;}</div>
	<div class="side left">.side{float:right;}</div>
</div>
<div class="footer">.footer</div>

優點:不存在結構和語義化問題,代碼量極少。

缺點:多個嵌套後,firefox某些情況會造成內容全選;IE中 mouseover 造成寬度改變時會出現最外層模塊有滾動條等,firefox早期版本會無故產生focus等。

(5) 父元素也設置浮動

優點:不存在結構和語義化問題,代碼量極少。

缺點:影響佈局,不可能一直浮動到body,不推薦。

(6) 父元素設置display:table;

優點:結構語義化完全正確,代碼量極少。

缺點:盒模型屬性改變,會造成一系列問題,得不償失,不推薦。

(6)使用:after 僞元素

​ 需要注意的是 :after是僞元素,不是僞類。由於IE6-7不支持:after,使用 zoom:1觸發 hasLayout

/* 權衡方法 */
/* IE8+ */
.clearfix:after {
    content:"."; 
    display:block; 
    height:0; 
    visibility:hidden; /* 或者overflow:hidden; 推薦visbility*/
    clear:both; 
}
/*  IE6 /IE7 */
.clearfix { *zoom:1; }

優點:結構和語義化完全正確,代碼量居中。

缺點:複用方式不當會造成代碼量增加。

2.2 清除浮動總結

通過上面的方法對比,我們不難發現,其實以上列舉的方法,無非有兩類:

  • 浮動元素後插入一個具有clear:both的元素
    • div等
    • 或者僞元素:after
  • 通過設置使得父元素BFC(IE8+)或haslayout(IE6/ IE7)。

在講述怎麼觸發BFC之前,我們應該瞭解以下什麼是BFC,這點國內的博客介紹較少,Block formatting contexts(塊級格式上下文)的簡稱。CSS3裏面對這個規範做了改動,稱之爲:flow root,並且對觸發條件進行了進一步說明。

2.2.1 如何觸發BFC?

  • float除了none以外的值
  • overflow ( hidden, auto, scroll)
  • display(table-cell, table-caption, inline-block)
  • position (absolute, fixed)
  • fieldset元素

display:table ;本身並不會創建BFC,但是它會產生匿名框(anonymous boxes),而匿名框中的display:table-cell可以創建新的BFC,換句話說,觸發塊級格式化上下文的是匿名框,而不是display:table。所以通過display:table和display:table-cell創建的BFC效果是不一樣的。

fieldset 元素在www.w3.org裏目前沒有任何有關這個觸發行爲的信息,直到HTML5標準裏纔出現。有些瀏覽器bugs(Webkit,Mozilla)提到過這個觸發行爲,但是沒有任何官方聲明。實際上,即使fieldset在大多數的瀏覽器上都能創建新的塊級格式化上下文,開發者也不應該把這當做是理所當然的。CSS 2.1沒有定義哪種屬性適用於表單控件,也沒有定義如何使用CSS來給它們添加樣式。用戶代理可能會給這些屬性應用CSS屬性,建議開發者們把這種支持當做實驗性質的,更高版本的CSS可能會進一步規範這個。

2.2.2 BFC特性

  1. 塊級格式化上下文會阻止外邊距疊加

    當兩個相鄰的塊框在同一個塊級格式化上下文中時,它們之間垂直方向的外邊距會發生疊加。換句話說,如果這兩個相鄰的塊框不屬於同一個塊級格式化上下文,那麼它們的外邊距就不會疊加。

  2. 塊級格式化上下文不會重疊浮動元素

    根據規定,一個塊級格式化上下文的邊框不能和它裏面的元素的外邊距重疊。這就意味着瀏覽器將會給塊級格式化上下文創建隱式的外邊距來阻止它和浮動元素的外邊距疊加。由於這個原因,當給一個挨着浮動的塊級格式化上下文添加負的外邊距時將會不起作用(Webkit和IE6在這點上有一個問題)。

  3. 塊級格式化上下文通常可以包含浮動

通俗地來說:創建了 BFC的元素就是一個獨立的盒子,裏面的子元素不會在佈局上影響外面的元素,反之亦然,同時BFC仍然屬於文檔中的普通流。----by 一絲絲涼

至此,您或許明白了爲什麼 overflow:hidden或者auto可以閉合浮動了,答案是因爲父元素創建了新的BFC。

對比BFC,IE6-7的顯示引擎使用的是一個稱爲佈局(layout)的內部概念,由於這個顯示引擎自身存在很多的缺陷,直接導致了IE6-7的很多顯示bug。當我們說一個元素“得到 layout”,或者說一個元素“擁有 layout” 的時候,我們的意思是指它的微軟專有屬性 hasLayout http://msdn.microsoft.com/worksh ... rties/haslayout.asp 爲此被設爲了 true 。IE6-7使用佈局的概念來控制元素的尺寸和定位,那些擁有佈局(have layout)的元素負責本身及其子元素的尺寸設置和定位。如果一個元素的 hasLayout 爲false,那麼它的尺寸和位置由最近擁有佈局的祖先元素控制。

2.2.3 觸發hasLayout的條件

在 IE7 中,overflow 也變成了一個 layout 觸發器:

  • overflow: hidden|scroll|auto ( 這個屬性在IE之前版本中沒有觸發 layout 的功能。 )

  • overflow-x|-y: hidden|scroll|auto (CSS3 盒模型中的屬性,尚未得到瀏覽器的廣泛支持。他們在之前IE版本中同樣沒有觸發 layout 的功能)

IE8 使用了全新的渲染引擎,刪除了 hasLayout 原本的功能,因此徹底杜絕了很多深惡痛絕的 bug,但 IE8~IE11 通過「document.documentElement.currentStyle.hasLayout」依然可以獲得 hasLayout 的標誌。

綜上所述:

在支持BFC的瀏覽器(IE8+,firefox,chrome,safari)通過創建新的BFC閉合浮動;在不支持 BFC的瀏覽器 (IE6-7),通過觸發 hasLayout 閉合浮動。

2.3 最佳實踐

在上文各種清除浮動的方法中,無疑最好的方法是第7種,即:

/* 權衡方法 */
/* IE8+ */
.clearfix:after {
    content:"."; 
    display:block; 
    height:0; 
    visibility:hidden; /* 或者overflow:hidden; 推薦visbility*/
    clear:both; 
}
/*  IE6 /IE7 */
.clearfix { *zoom:1; }

下面詳細說說該方法。

  1. display:block 使生成的元素以塊級元素顯示,佔滿剩餘空間;

  2. height:0 避免生成內容破壞原有佈局的高度。

  3. visibility:hidden 使生成的內容不可見,並允許可能被生成內容蓋住的內容可以進行點擊和交互;

4)通過 content:"."生成內容作爲最後一個元素,至於content裏面是點還是其他都是可以的,例如oocss裏面就有經典的 content:"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",有些版本可能content 裏面內容爲空,博主一絲冰涼不推薦這樣做的,firefox直到7.0 content:”" 仍然會產生額外的空隙;

5)zoom:1 觸發IE hasLayout。

通過分析發現,除了clear:both用來閉合浮動的,其他代碼無非都是爲了隱藏掉content生成的內容,這也就是其他版本的閉合浮動爲什麼會有font-size:0; line-height:0;。

最佳實踐

/*更好的方法,代碼量更少*/
/* IE8+ */
.clearfix:before,
.clearfix:after {
	content:"";
	display:table;
	clear:both;
} 
/*  IE6 /IE7 */
.clearfix {	*zoom:1; }

由Nicolas Gallagher 大溼提出來的,原文:A new micro clearfix hack,該方法不存在firefox中空隙的問題。

需要注意的是:

上面的方法用到了 :before僞元素,很多人對這個有些迷惑,到底我什麼時候需要用before呢?這裏需要了解它的作用,即用來處理margin邊距重疊的,由於內部元素 float 創建了BFC,導致內部元素的margin-top和 上一個盒子的margin-bottom 發生疊加。如果這不是你所希望的,那麼就可以加上before,如果只是單純的閉合浮動,after就夠了!並不是如同大漠《Clear Float》一文所說的:但只使用clearfix:after時在跨瀏覽器兼容問題會存在一個垂直邊距疊加的bug,這不是bug,是BFC應該有的特性。

需要注意,清除浮動不應該被濫用。通常只應該運用在浮動子元素的父級元素上。

3. 浮動與流體佈局

合理的使用浮動,可以實現非常棒的流體佈局。結合張鑫旭在慕課網的課程理解。

浮動與流體佈局-張鑫旭

html結構:

<div class="mib_x mib_resize">
        <div class="mib_list">
            <a href="http://t.sina.com.cn/xuruoxuan" class="mib_head_a">
                <img id="mibHeadImg" title="徐若瑄VIVIAN" src="http://img.mukewang.com/53e2e9470001dfd200500050.jpg">
            </a>
            <div class="mib_cell">
                <p class="mib_sms"><a title="徐若瑄VIVIAN" href="#">徐若瑄VIVIAN<i title="新浪認證" class="mib_vip"></i></a>:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~</p>
                <div class="feed_img"><img src="http://img.mukewang.com/53e2e9b10001948000890120.jpg" height="120"></div>
            </div>    
        </div>
</div>

1)浮動與兩側皆自適應的流體佈局

body { 
    font-size: 14px; 
    background-color: #DDF3F7; 
    color: #333; 
}
a { 
    color: #0082CB; 
    text-decoration: none; 
}
p { margin: 0; } 
img { border: 0; }

.mib_body { 
    width: 600px; 
    margin-left: auto;
    margin-right: auto; 
}
.mib_x { 
    margin-bottom: 10px; 
    background-color: #fff; 
}
.mib_list { padding: 20px; }
.mib_resize { 
    overflow: auto; 
    resize: both; 
}
.mib_vip { 
    display: inline-block; 
    width: 11px; 
    height: 10px; 
    margin-left: 1px; 
    background: url(data:image/gif;base64,R0lGODlhCwAKAJEDAPyZCveDBuJmBP///yH5BAEAAAMALAAAAAALAAoAAAIdhD1zopgTXgMpsBdylVCPK2UCKI0j95hoRa0NVwAAOw==); 
}

.mib_head_a { 
    float: left; 
    margin-right: 20px; 
}

2)浮動與右側尺寸固定的流體佈局

<body>
<div id="mibBody" class="mib_body">
    <div class="mib_x mib_resize">
        <div class="mib_list">
            <a href="http://t.sina.com.cn/xuruoxuan" class="mib_head_r">
                <img title="徐若瑄VIVIAN" src="http://img.mukewang.com/53e2e9470001dfd200500050.jpg">
            </a>
            <div class="mib_feed_flow">
                <p class="mib_sms"><a title="徐若瑄VIVIAN" href="#">徐若瑄VIVIAN<i title="新浪認證" class="mib_vip"></i></a>:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~</p>
                <div class="feed_img"><img src="http://img.mukewang.com/53e2e9b10001948000890120.jpg" height="120"></div>
            </div>
        </div>
    </div>
    <div class="mib_x mib_resize">
        <div class="mib_list">
        	<div class="mib_full_float">
                <div class="mib_feed_flow">
                    <p class="mib_sms"><a title="徐若瑄VIVIAN" href="#">徐若瑄VIVIAN<i title="新浪認證" class="mib_vip"></i></a>:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~</p>
                    <div class="feed_img"><img src="http://img.mukewang.com/53e2e9b10001948000890120.jpg" height="120"></div>
                </div>
            </div>
            <a href="http://t.sina.com.cn/xuruoxuan" class="mib_head_l">
                <img title="徐若瑄VIVIAN" src="http://img.mukewang.com/53e2e9470001dfd200500050.jpg">
            </a>
        </div>
    </div>
</div>
</body>
ody { font-size: 14px; background-color: #DDF3F7; color: #333; }
a { color: #0082CB; text-decoration: none; }
p { margin: 0; } img { border: 0; }

.mib_body { width: 600px; margin-left: auto; margin-right: auto; }
.mib_x { margin-bottom: 10px; background-color: #fff; }
.mib_list { padding: 20px; overflow: hidden; _zoom: 1; resize: none; }
.mib_resize { overflow: auto; resize: both; }
.mib_vip { display: inline-block; width: 11px; height: 10px; margin-left: 1px; background: url(data:image/gif;base64,R0lGODlhCwAKAJEDAPyZCveDBuJmBP///yH5BAEAAAMALAAAAAALAAoAAAIdhD1zopgTXgMpsBdylVCPK2UCKI0j95hoRa0NVwAAOw==); }

/* 下面這個是右浮動,改變DOM位置的流體佈局寫法 */
.mib_head_r { width: 56px; float: right; }
.mib_feed_flow { margin-right: 76px; }
/* 下面這個是左浮動,不改變DOM位置的流體佈局寫法 */
.mib_full_float { width: 100%; float: left; }
.mib_head_l { width: 56px; float: left; margin-left: -56px;}

3)浮動與單側尺寸固定的流體佈局

<div id="mibBody" class="mib_body">
    <div class="mib_x">
        <div class="mib_list">
            <a href="http://t.sina.com.cn/xuruoxuan" class="mib_head_a">
                <img title="徐若瑄VIVIAN" src="http://img.mukewang.com/53e2e9470001dfd200500050.jpg">
            </a>
            <div class="mib_feed_fixed">
                <p class="mib_sms"><a title="徐若瑄VIVIAN" href="#">徐若瑄VIVIAN<i title="新浪認證" class="mib_vip"></i></a>:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~</p>
                <div class="feed_img"><img src="http://img.mukewang.com/53e2e9b10001948000890120.jpg" height="120"></div>
            </div>
        </div>
    </div>
    <div class="mib_x">
        <div class="mib_list">
            <a href="http://t.sina.com.cn/xuruoxuan" class="mib_head_a">
                <img title="徐若瑄VIVIAN" src="http://img.mukewang.com/53e2e9470001dfd200500050.jpg">
            </a>
            <div class="mib_feed_flow">
                <p class="mib_sms"><a title="徐若瑄VIVIAN" href="#">徐若瑄VIVIAN<i title="新浪認證" class="mib_vip"></i></a>:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~</p>
                <div class="feed_img"><img src="http://img.mukewang.com/53e2e9b10001948000890120.jpg" height="120"></div>
            </div>
        </div>
    </div>

</div>
body { font-size: 14px; background-color: #DDF3F7; color: #333; }
a { color: #0082CB; text-decoration: none; }
p { margin: 0; } img { border: 0; }

.mib_body { width: 600px; margin-left: auto; margin-right: auto; -webkit-transition: width .35s; transition: width .35s; }
.mib_x { margin-bottom: 10px; background-color: #fff; }
.mib_list { padding: 20px; overflow: hidden; _zoom: 1; }
.mib_vip { display: inline-block; width: 11px; height: 10px; margin-left: 1px; background: url(data:image/gif;base64,R0lGODlhCwAKAJEDAPyZCveDBuJmBP///yH5BAEAAAMALAAAAAALAAoAAAIdhD1zopgTXgMpsBdylVCPK2UCKI0j95hoRa0NVwAAOw==); }

.mib_head_a { width: 56px; float: left; }
/* 下面這個是固定佈局寫法 */
.mib_feed_fixed { width: 484px; float: right; }
/* 下面這個是流體佈局寫法 */
.mib_feed_flow { margin-left: 76px; }

4. 小結

本文從浮動設計初衷出發,講述了浮動的特性,包括包裹性與破壞性;由於浮動給佈局帶來的影響,需要清理這種影響,故又給出了多種清理浮動的方法,並最終給出了最佳實踐。同時,講述清理浮動方法時,也給出了BFC與haslayout的部分知識,方便讀者理解。希望讀完這篇文章能給大家一些益處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章