1. 程式人生 > >深入理解CSS定位—浮動模型

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

前面我們講到了絕對定位,在這篇文章中,我們將講到3種定位模型中的浮動模型。主要參考 - 張鑫旭在慕課網的 [深入理解float](http://www.imooc.com/learn/121) - [那些年我們一起清過的浮動---by 一絲絲涼](http://www.iyunlu.com/view/css-xhtml/55.html) - 精通CSS **注意**:第二小節基本參考一絲絲涼的內容,看過這篇就可以略過我的那部分內容。 ## 1. 浮動 浮動:**浮動的框可以左右移動,直到它的外邊緣碰到包含框或另一個浮動框的邊緣**。和絕對定位元素一樣,使用浮動後,該元素也會脫離文件流,即**浮動框不屬於文件中的普通流**。**當一個元素浮動之後,不會影響到塊級框的佈局而只會影響內聯框(通常是文字)的排列,文件中的普通流就會表現得和浮動框不存在一樣,當浮動框高度超出包含框的時候,也就會出現包含框不會自動伸高來閉合浮動元素(“高度塌陷”現象)。**顧名思義,就是漂浮於普通流之上,像浮雲一樣,但是隻能左右浮動。 正是因為浮動的這種特性,導致本屬於普通流中的元素浮動之後,包含框內部由於不存在其他普通流元素了,也就表現出高度為0(高度塌陷)。在實際佈局中,往往這並不是我們所希望的,所以需要**閉合浮動元素**,使其包含框表現出正常的高度。 ### 1.1 浮動設計的初衷與特性 **浮動設計的初衷是為了實現文字環繞效果**。明白了浮動的設計初衷,我們就能明白浮動的特性表現了。浮動具有以下兩個特性: - 包裹性 - 破壞性 單純只是說浮動的特性:包裹性與破壞性,很多小夥伴可能會很迷糊,不知所云。那麼下面我們結合案例來說明以下,便於理解。 **包裹性** 什麼是包裹性呢?這個需要結合栗子理解。下面是一個普普通通的div小青年,給它加上背景色,可以看到,獨佔一行(塊級元素特性)。同樣的div,給它加上float:left,可以看到,框收縮了,緊緊包裹住它的內容。 ```css body { margin: 0; padding:0; } .container { width: 800px; float: left; margin: 0 auto; } .normal { background-color: salmon; } .flo { float: left; background-color: seagreen; } ``` ```html 普普通通的div小青年 浮動小青年 ``` ![](https://img2020.cnblogs.com/blog/1083040/202005/1083040-20200512200012019-784677135.png) 具有包裹性的其它小夥伴: - display:inline-block/table-cell/... - position:absolute/fixed/sticky - overflow:hidden/scroll **破壞性** 正如前文所說,*“使用浮動後,元素會脫離文件的普通流,它不會影響到塊級框的佈局而只會影響內聯框(通常是文字)的排列,文件中的普通流就會表現得和浮動框不存在一樣,當浮動框高度超出包含框的時候,也就會出現包含框不會自動伸高來閉合浮動元素(“高度塌陷”現象)。“* 栗子: ```html 浮動小青年 ``` 正常情況(不給類flo加浮動): ![](https://img2020.cnblogs.com/blog/1083040/202005/1083040-20200512200052160-1734949069.png) 給div加上浮動後,容器“高度塌陷”。 ![](https://img2020.cnblogs.com/blog/1083040/202005/1083040-20200512200101839-1545160964.png) 具有破壞性的其它小夥伴: - display:none - position:absolute/fixed/sticky ## 2. 清除浮動(更準確,閉合浮動) 由於浮動的特性,所以運用它來佈局時候我們通常需要清除浮動,更嚴謹的說,是閉合浮動:使浮動元素閉合,從而減少浮動的影響。 #### 2.1 清除浮動的方法 清除浮動的各種方法: (1)**新增額外的標籤** ​ 通過在浮動元素末尾新增一個空的標籤例如div元素附加clearLboth;css屬性,其他標籤br等亦可。 ```HTML

1)新增額外標籤

.main{float:left;} .side{float:right;} .footer ``` **優點**:通俗易懂,容易掌握 **缺點**:可以想象通過此方法,會新增多少無意義的空標籤,有違結構與表現的分離,在後期維護中將是噩夢,這是堅決不能忍受的,建議不要使用。 (2)**使用 br標籤和其自身的 html屬性** ​ 這個方法有些小眾,br 有 clear=“all | left | right | none” 屬性 ```html

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

.main{float:left;} .side{float:right;}
.footer ``` **優點**:比空標籤方式語義稍強,程式碼量較少 **缺點**:同樣有違結構與表現的分離,不推薦使用 (3) **父元素設定 overflow:hidden**; ​ 通過設定父元素overflow值設定為hidden;在IE6中還需要觸發 hasLayout ,例如 zoom:1; ```html

3)父元素設定 overflow

.main{float:left;} .side{float:right;} .footer ``` **優點**:不存在結構和語義化問題,程式碼量極少 **缺點**:內容增多時候容易造成不會自動換行導致內容被隱藏掉,無法顯示需要溢位的元素;04年*POPO*就發現[overflow:hidden會導致中鍵失效](http://plod.popoever.com/archives/000309.html),所以還是不要使用了. (4) **父元素設定 overflow:auto 屬性**
​ 同樣*IE6*需要觸發*hasLayout*,和3差不多 ```html

3)父元素設定 overflow

.main{float:left;} .side{float:right;} .footer ``` **優點**:不存在結構和語義化問題,程式碼量極少。 **缺點**:多個巢狀後,firefox某些情況會造成內容全選;IE中 mouseover 造成寬度改變時會出現最外層模組有滾動條等,firefox早期版本會無故產生focus等。 (5) **父元素也設定浮動** **優點**:不存在結構和語義化問題,程式碼量極少。 **缺點**:影響佈局,不可能一直浮動到body,不推薦。 (6) **父元素設定display:table;**
**優點**:結構語義化完全正確,程式碼量極少。 **缺點**:盒模型屬性改變,會造成一系列問題,得不償失,不推薦。 (6)**使用:after 偽元素** ​ 需要注意的是 :after是偽元素,不是偽類。**由於IE6-7不支援:after,使用 zoom:1觸發 hasLayout**。 ```css /* 權衡方法 */ /* 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](https://www.w3.org/TR/CSS21/visuren.html#block-formatting)(塊級格式上下文)的簡稱。CSS3裡面對這個規範做了改動,稱之為:[flow root](http://www.w3.org/TR/css3-box/#block-level0),並且對觸發條件進行了進一步說明。 **2.2.1 如何觸發BFC?** - *float除了none以外的值* - *overflow ( hidden, auto, scroll)* - *display(table-cell, table-caption, inline-block)* - *position (absolute, fixed)* - *fieldset元素* display:table ;本身並不會建立BFC,但是它會產生[匿名框](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes)(anonymous boxes),而匿名框中的display:table-cell可以建立新的BFC,換句話說,觸發塊級格式化上下文的是匿名框,而不是display:table。所以通過display:table和display:table-cell建立的BFC效果是不一樣的。 fieldset 元素在www.w3.org裡目前沒有任何有關這個觸發行為的資訊,直到[HTML5](http://jeehon.info/log/2011/11/11/block-formatting-contexts塊級格式化上下文/www.w3.org/TR/html5/the-xhtml-syntax.html#the-fieldset-element-0)標準裡才出現。有些瀏覽器bugs(Webkit,Mozilla)提到過這個觸發行為,但是沒有任何官方宣告。實際上,即使fieldset在大多數的瀏覽器上都能建立新的塊級格式化上下文,開發者也不應該把這當做是理所當然的。`CSS 2.1沒有定義哪種屬性適用於表單控制元件,也沒有定義如何使用CSS來給它們新增樣式。使用者代理可能會給這些屬性應用CSS屬性,建議開發者們把這種支援當做實驗性質的,更高版本的CSS可能會進一步規範這個。` **2.2.2 BFC特性** 1. **塊級格式化上下文會阻止外邊距疊加** 當兩個相鄰的塊框在同一個塊級格式化上下文中時,它們之間垂直方向的外邊距會發生[疊加](http://www.w3.org/TR/CSS21/box.html#collapsing-margins)。換句話說,如果這兩個相鄰的塊框不屬於同一個塊級格式化上下文,那麼它們的外邊距就不會疊加。 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](http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/haslayout.asp) 為此被設為了 true 。IE6-7使用佈局的概念來控制元素的尺寸和定位,那些擁有佈局(have layout)的元素負責本身及其子元素的尺寸設定和定位。如果一個元素的 hasLayout 為false,那麼它的尺寸和位置由最近擁有佈局的祖先元素控制。 **2.2.3 觸發hasLayout的條件**: - position: absolute - float: left|right - display: inline-block - width: 除 “auto” 外的任意值 - height: 除 “auto” 外的任意值 (例如很多人閉合浮動會用到 height: 1% ) - zoom: 除 “normal” 外的任意值 (MSDN) [http://msdn.microsoft.com/worksh ... properties/zoom.asp](http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/zoom.asp) - writing-mode: tb-rl (MSDN) [http://msdn.microsoft.com/worksh ... ies/writingmode.asp](http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/writingmode.asp) 在 IE7 中,overflow 也變成了一個 layout 觸發器: - overflow: hidden|scroll|auto ( 這個屬性在IE之前版本中沒有觸發 layout 的功能。 ) - overflow-x|-y: hidden|scroll|auto (CSS3 盒模型中的屬性,尚未得到瀏覽器的廣泛支援。他們在之前IE版本中同樣沒有觸發 layout 的功能) IE8 使用了全新的渲染引擎,[刪除了 hasLayout 原本的功能](http://msdn.microsoft.com/zh-cn/library/cc304082(v=VS.85).aspx#浮動),因此徹底杜絕了很多深惡痛絕的 bug,但 IE8~IE11 通過「document.documentElement.currentStyle.hasLayout」依然可以獲得 hasLayout 的標誌。 綜上所述: 在支援BFC的瀏覽器(IE8+,firefox,chrome,safari)通過建立新的BFC閉合浮動;在不支援 BFC的瀏覽器 (IE6-7),通過觸發 hasLayout 閉合浮動。 #### 2.3 最佳實踐 在上文各種清除浮動的方法中,無疑最好的方法是第7種,即: ```css /* 權衡方法 */ /* 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;。 **最佳實踐** ```css /*更好的方法,程式碼量更少*/ /* IE8+ */ .clearfix:before, .clearfix:after { content:""; display:table; clear:both; } /* IE6 /IE7 */ .clearfix { *zoom:1; } ``` 由Nicolas Gallagher 大溼提出來的,原文[:A new micro clearfix hack](http://nicolasgallagher.com/micro-clearfix-hack/),該方法不存在firefox中空隙的問題。 **需要注意的是:** 上面的方法用到了 :before偽元素,很多人對這個有些迷惑,到底我什麼時候需要用before呢?這裡需要了解它的作用,**即用來處理margin邊距重疊的**,由於內部元素 float 建立了BFC,導致內部元素的margin-top和 上一個盒子的margin-bottom 發生疊加。如果這不是你所希望的,那麼就可以加上before,如果只是單純的閉合浮動,after就夠了!並不是如同大漠[《Clear Float》](http://www.w3cplus.com/css/clear-float)一文所說的:但只使用clearfix:after時在跨瀏覽器相容問題會存在一個垂直邊距疊加的bug,這不是bug,是BFC應該有的特性。 **需要注意**,清除浮動不應該被濫用。通常只應該運用在浮動子元素的父級元素上。 ### 3. 浮動與流體佈局 合理的使用浮動,可以實現非常棒的流體佈局。結合張鑫旭在慕課網的課程理解。 [浮動與流體佈局-張鑫旭](https://www.imooc.com/video/2886) html結構: ```html

徐若瑄VIVIAN:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~

``` 1)浮動與兩側皆自適應的流體佈局 ```css 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)浮動與右側尺寸固定的流體佈局 ```html

徐若瑄VIVIAN:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~

徐若瑄VIVIAN:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~

``` ```css 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)浮動與單側尺寸固定的流體佈局 ```html

徐若瑄VIVIAN:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~

徐若瑄VIVIAN:一個人的晚餐!茶泡飯!飯、飯、飯… 今日不減肥,先把病治好再說! 我認真吃完這,燒就會退了吧?! 開動啦~~~~~~~~~~~~~~~~~~

``` ```css 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的部分知識,方便讀者理解。希望讀完這篇文章能給大家一些