浮動,從誕生那天起,它就是個特別的屬性——既為網(wǎng)頁布局帶來新的方法,卻又隨之產(chǎn)生一系列的問題。當然,隨著時間的推移,這些問題終究有了一些出色的解決方案,小編要在這里詳細介紹的,除了是這些解決方案,還有其中的原理。
一.什么是清除浮動?
1.浮動的缺陷
在了解如何清除浮動之前,先介紹為什么需要清除浮動。如本文開頭所說的,浮動雖然可以便于頁面布局,但同時會產(chǎn)生一些問題,也就是我們常說的“副作用”。而一個元素設置了浮動(即 float 值為 left, right 或 inherit 并從父元素上繼承 left 或 right 值)的常見缺陷是——影響它的兄弟元素的位置和父元素產(chǎn)生高度塌陷,下面對這兩個問題展開說明。
一個元素設置了浮動后,會影響它的兄弟元素,具體的影響方式較為復雜,這要視乎這些兄弟元素是塊級元素還是內(nèi)聯(lián)元素,若是塊級元素會無視這個浮動的塊框,也就是我們平時看到的效果——使到自身盡可能與這個浮動元素處于同一行,導致被浮動元素覆蓋,除非這些 div 設置了寬度,并且父元素的寬度不足以包含它們,這樣兄弟元素才會被強制換行;若是內(nèi)聯(lián)元素,則會盡可能圍繞浮動元素。
另外,浮動的元素脫離了普通流,這樣使得包含它的父元素并不會因為這個浮動元素的存在而自動撐高,這樣就會造成高度塌陷。
下面是演示效果圖
關于這幾點的更多說明,請看Demo。
很顯然,無論是影響兄弟元素還是高度塌陷的問題,都不是我們使用浮動的目的,設置浮動,只是為了改變一個元素的布局,但最終的結(jié)果卻造成了更多不必要的影響,這不利于布局,因此我們需要清除這些額外的影響,也就是本文要介紹的清除浮動,其實更加準確的說,是清除浮動帶來的額外影響。
2.清除浮動的常見方法
了解了為什么要清除浮動后,這里可以開始介紹清除浮動的常見方法了,不過這里并不急于探討這些方法的原理,首先列出幾種常見清除浮動的方法,再作探討。
說起清除浮動,大家肯定會想起 clear: both ,的確,這是 CSS 中清除浮動的屬性,clear 有 both/left/right/none/inherit 幾個屬性值,分別代表在元素左右兩側(cè)不允許出現(xiàn)浮動元素/左側(cè)不允許出現(xiàn)浮動元素/右側(cè)不允許出現(xiàn)浮動元素/不清除浮動/繼承父元素的值。
如下圖為清除浮動的例子:
也可以看Demo。
從例子中可以看出,設置了 clear: both (當然在該例子中也可以為 clear: left)的元素不會跟浮動元素同行,并且會占據(jù)新的一整行,而不是根據(jù)內(nèi)容來自動調(diào)整寬度。之所以會這樣,要從 clear 的原理說起,clear 會為元素添加足夠的空白空間,使到該元素的位置會放置在它前一個浮動元素之下,這跟增加元素外邊距使到元素占據(jù)滿行而強制換行的效果是一樣的,事實上在 CSS1 和 CSS2 中,清除浮動正是通過自動為清除元素(即設置了 clear 屬性的元素)增加外邊距實現(xiàn)的,從 CSS 2.1 開始改為增加額外的空白空間,不改變外邊距。現(xiàn)在大家應該清楚了,既然是增加足夠的空間使到元素換行,那么最穩(wěn)妥的辦法就是使到該元素占據(jù)一整行,也就是 Demo 中的效果。
現(xiàn)在清除了浮動,但是,這只是清除了浮動對于兄弟元素的影響,而高度塌陷的問題還沒有解決,因此,我們需要更高級的清除浮動——閉合浮動。
為什么叫閉合浮動?因為浮動的元素脫離了普通流,因此對于它的父元素,它并沒有閉合,這時候就需要閉合浮動了。這個問題的解決方法經(jīng)過多年的發(fā)展,已經(jīng)有了比較完善的方法,下面為大家詳細介紹三種常用方法。
(1) 空 div 方法
這是較為古老的方法了,除了 div ,也有使用其他標簽的,但 div 更為適用,因為除了瀏覽器賦予它的 display: block 外,它沒有其他的樣式了,也不會有特殊的功能,干干凈凈。這里插一段題外話,display: block 是瀏覽器賦予 div 的,存在于瀏覽器的 user agent stylesheet ,而不是 div 默認 display 的值就為 block ,在 W3C 中,所有的 HTML 標簽 display 的默認值都為 inline 。
下面代碼中使用到的 box main left aside 為預先設置了相關 CSS 的類,具體可以查看 Demo 的源碼,在其他例子中也是如此。
我設置了左浮動 float: left
我是頁腳,我的上面添加了一個設置了 clear: both 的空 div
效果如圖:
也可以看Demo。
空 div 方法很方便,但是加入了沒有涵義的 div ,這違背了結(jié)構(gòu)與表現(xiàn)分離的原則,并且后期維護也不方便。
(2) overflow 方法
在浮動元素的父元素上設置了 overflow 的值為 hidden 或 auto ,可以閉合浮動。另外在 IE6 中還需要觸發(fā) hasLayout ,例如為父元素設置容器寬高或設置 zoom:1
我設置了左浮動 float: left
我是頁腳,但是我也設置了左浮動。
效果如圖:
也可以看Demo。
這個方法相對前者更加方便,也更加符合語義要求,只是 overflow 并不是為了閉合浮動而設計的,因此當元素內(nèi)包含會超出父元素邊界的子元素時,可能會覆蓋掉有用的子元素,或是產(chǎn)生了多余的滾動條。這也是在 overflow 方法誕生后依然需要尋找更佳方法的原因。
(3) 使用 :after 偽元素的方法
該方法來源于positioniseverything, 結(jié)合 :after 偽元素(注意這不是偽類,而是偽元素,代表一個元素之后最近的元素)和 IEhack ,可以完美兼容當前主流的各大瀏覽器,這里的 IEhack 指的是觸發(fā) hasLayout ,具體請看下面的方法。
.clearfix {/* 觸發(fā) hasLayout */ zoom: 1; }
.clearfix:after {content: "."; display: block; height: 0; clear: both; visibility: hidden; }
我設置了左浮動 float: left
我是頁腳,但是我也設置了左浮動。
顯然,相對來說,這個辦法不但完美兼容主流瀏覽器,并且也很方便,使用重用的類,可以減輕代碼編寫,另外網(wǎng)頁的結(jié)構(gòu)也會更加清晰。
效果如圖:
也可以看Demo。
二.清除浮動方法的實質(zhì) —— CSS clear 與 BFC 特性
通過上面的例子,我們不難發(fā)現(xiàn)清除浮動的方法可以分成兩類:
一是利用 clear 屬性,包括在浮動元素末尾添加一個帶有 clear: both 屬性的空 div 來閉合元素,其實利用 :after 偽元素的方法也是在元素末尾添加一個內(nèi)容為一個點并帶有 clear: both 屬性的元素實現(xiàn)的。
二是觸發(fā)浮動元素父元素的 BFC (Block Formatting Contexts, 塊級格式化上下文),使到該父元素可以包含浮動元素,關于這一點,下面 Kayo 為大家進行詳細的介紹。
BFC 在 CSS 的可視化格式模型 (Visual Formatting Model) 中具有非常重要的地位,很多開發(fā)者因為不了解 BFC 的特性而在實際開發(fā)中產(chǎn)生很多讓人感到莫名其妙的問題。盡管如此,因為 BFC 涉及 CSS 中很少接觸的部分,因此國內(nèi)的相關介紹很少,這里展開說明一下。
1.BFC 是什么?
BFC (Block Formatting Contexts) 即塊級格式化上下文,從樣式上看,它與普通的容器沒有什么區(qū)別,但是從功能上,BFC 可以看作是隔離了的獨立容器,容器里面的元素不會在布局上影響到外面的元素,并且 BFC 具有普通容器沒有的一些特性,例如可以包含浮動元素,上面的第二類方法(如 overflow 方法)就是觸發(fā)了父元素的 BFC ,使到它可以包含浮動元素,從而防止出現(xiàn)高度塌陷的問題。
2.如何觸發(fā) BFC
觸發(fā) BFC 的條件如下:
浮動元素,float 除 none 以外的值
絕對定位元素,position(absolute,fixed)
display 為以下其中之一的值 inline-blocks,table-cells,table-captions
overflow 除了 visible 以外的值(hidden,auto,scroll)
在 CSS3 中,BFC 叫做 Flow Root,并增加了一些觸發(fā)條件:
display 的 table-caption 值
position 的 fixed 值,其實 fixed 是 absolute 的一個子類,因此在 CSS2.1 中使用這個值也會觸發(fā) BFC ,只是在 CSS3 中更加明確了這一點。
3.BFC 的特性
BFC 主要有三個特性:
(1) BFC 會阻止外邊距折疊
兩個相連的 div 在垂直上的外邊距會發(fā)生疊加,有些書籍會把這個情況列作 bug ,這里 Kayo 并不同意,這種折疊雖然會給不熟悉 CSS 布局的開發(fā)者帶來一些不便,但實際上它具有完整且具體的折疊規(guī)則,并且在主流瀏覽器中都存在,因此更認為這應該是 CSS 的特性。當然,在實際開發(fā)中,或許我們有時會不需要這種折疊,這時可以利用 BFC 的其中一個特性——阻止外邊距疊加。
(2) BFC 可以包含浮動的元素
這也正是上面使用 overflow: hidden 與 overflow: auto 方法閉合浮動的原理,使用 overflow: hidden 或 overflow: auto 觸發(fā)浮動元素父元素的 BFC 特性,從而可以包含浮動元素,閉合浮動。
W3C 的原文是“'Auto' heights for block formatting context roots”,也就是 BFC 會根據(jù)子元素的情況自動適應高度,即使其子元素中包括浮動元素。
但是 IE6-7 并不支持 W3C 的 BFC ,而是使用自產(chǎn)的 hasLayout 。從表現(xiàn)上來說,它跟 BFC 很相似,只是 hasLayout 自身存在很多問題,導致了 IE6-7 中一系列的 bug 。觸發(fā) hasLayout 的條件與觸發(fā) BFC 有些相似,具體情況 Kayo 會另寫文章介紹。這里 Kayo 推薦為元素設置 IE 特有的 CSS 屬性 zoom: 1 觸發(fā) hasLayout ,zoom 用于設置或檢索元素的縮放比例,值為“1”即使用元素的實際尺寸,使用 zoom: 1 既可以觸發(fā) hasLayout 又不會對元素造成其他影響,相對來說會更為方便。
(3) BFC 可以阻止元素被浮動元素覆蓋
如上面所說,浮動元素的塊狀兄弟元素會無視浮動元素的位置,盡量占滿一整行,這樣就會被浮動元素覆蓋,為該兄弟元素觸發(fā) BFC 后可以阻止這種情況的發(fā)生。
為了說明 BFC 對于清除浮動的本質(zhì),在這里使用了較大的篇幅介紹了 BFC ,但 BFC 并不是本文要說明的中心,并且 BFC 的機制也相當復雜,因此 會基于以上 BFC 的內(nèi)容另寫一篇更詳細的文章介紹 BFC ,并制作 Demo 說明實際情況。
三.清除浮動的更多方法
在了解了清除浮動的實際原理后,我們不難想象,清除浮動的方法并不只上面提到的三種,例如,利用 BFC 特性,還可以使用以下的方法觸發(fā) BFC 并清除浮動。
給浮動元素的父元素添加浮動,但是這樣需要一直浮動到 body ,不建議采取該方法。
給浮動元素的父元素添加 display: table-cells ,但是這樣無疑改變了盒子模型,也不建議使用。
可以看出,以上這些方法雖然也比較方便,但同時也有很明顯的缺點,這也導致了上面三種方法會更加適合實際項目中使用。
結(jié)合語義化的要求,在實際的項目中,Kayo 建議可以使用 overflow 方法或 :after 偽元素方法。使用 overflow 方法,較為方便,在如內(nèi)部元素全部為浮動元素,并且內(nèi)容不會超出父元素框等情況可以直接采用 overflow 方法,但該方法畢竟會觸發(fā) BFC ,上面已經(jīng)提到,BFC 的特性是有多個的,為了避免不必要的影響,如果實際需要清除浮動元素的布局比較復雜,可以直接采用 :after 偽元素方法。