一、開篇之言
要說web上實現兩欄自適應佈局的方法,一雙手都數不過來。不知大家有沒有細想過,爲什麼這些方法可以實現自適應佈局呢?
本文就將深入探討下流體特性和BFC特性下的兩欄自適應佈局,還是針對傳統佈局。一些現代佈局,如彈性盒子模型佈局(Flexbox Layout),格柵佈局(Grid Layout)不在本文探討之類。
有些人看了個標題,以及看了前面一兩段,發現,都是我知道的概念嘛,什麼流動性,什麼BFC~~於是,就悻悻離開了。這就是我們常說的浮躁,保持一顆謙遜的心,細細閱讀,你會發現,其中一定有你所沒有關注過的地方,所謂三人行必有我師。沒錯,這句話就是寫給你看的,同時也是自我內省與監督。
二、塊狀元素的流體特性與自適應佈局
流體特性
塊狀水平元素,如div
元素(下同),在默認情況下(非浮動、絕對定位等),水平方向會自動填滿外部的容器;如果有margin-left/margin-right
, padding-left/padding-right
, border-left-width/border-right-width
等,實際內容區域會響應變窄。
一圖勝千言,一例勝千圖。可參考下面例子,感受下div
元素的流體特性:
圖片寬度一直width:100%
,依次點擊3個按鈕,結果隨着margin
, padding
, border
的出現,其可用寬度自動跟着減小,形成了自適應效果。就像放在容器中的水流一樣,內容區域會隨着margin
, padding
, border
的出現自動填滿剩餘空間,這就是塊狀元素的流體特性。
流體特性
下面,我們稍微做一個調整,div
距離容器左側margin
150
像素,裏面的圖片同樣100%
自適應內容區域。HTML如下:
.flow-box { width: 500px; background-color: #eee; overflow:auto; resize:horizontal; } .flow-content { margin-left: 150px; }
<div class="flow-box"> <div class="flow-content"><img src="mm1.jpg" width="100%" height="190"></div> </div>
圖片右下角有兩道斜槓,我們可以resize拉伸(現代瀏覽器,且非移動訪問),會發現,左側永遠150像素留白,而圖片隨着容器寬度變化而自適應變化了。
此時,我們需要好好利用左側150像素的留白間距,豈不是就可以實現兩欄自適應效果!?
爲了不影響原本的流體特性,我們可以使用破壞性屬性,如浮動(float:left),或者絕對定位(position:absolute)。
我們直接HTML如下調整即可:
<div class="flow-box"> <img src="mm1.jpg" width="128" style="float:left;"> <div class="flow-content"><img src="mm1.jpg" width="100%" height="190"></div> </div>
<div class="flow-box"> <img src="mm1.jpg" width="128" style="position:absolute;"> <div class="flow-content"><img src="mm1.jpg" width="100%" height="190"></div> </div>
結果分別如下:
當然,你可以左側有多個浮動,或者左浮動+右浮動。於是,我們不僅可以實現兩欄自適應效果,多欄自適應效果也不在話下。
然而,利用塊狀元素流體特性實現的自適應佈局有個不足,就是,我們需要知道浮動或絕對定位內容的尺寸。然後,流體內容纔能有對應的margin
或padding
或border
值進行位置修正。於是,問題來了,我們沒法單純使用一個公用的類名,類似.clearfix
這樣,整站通用。因爲不同自適應場景的留白距離是不一樣的。
此時,我們可以利用塊狀元素的BFC特定實現更強大更智能的多欄自適應佈局(本文重點)。
三、元素的BFC特性與自適應佈局
1. BFC元素簡介與基本表現
BFC全稱”Block Formatting Context”, 中文爲“塊級格式化上下文”。啪啦啪啦特性什麼的,一言難盡,大家可以自行去查找,我這裏不詳述,免得亂了主次,總之,記住這麼一句話:BFC元素特性表現原則就是,內部子元素再怎麼翻江倒海,翻雲覆雨都不會影響外部的元素。所以,避免margin穿透啊,清除浮動什麼的也好理解了。
什麼時候會觸發BFC呢?常見的如下:
float
的值不爲none
。overflow
的值爲auto
,scroll
或hidden
。display
的值爲table-cell
,table-caption
,inline-block
中的任何一個。position
的值不爲relative
和static
。
BFC特性很多,而我們這裏,只關心一個,和float
元素做相鄰兄弟時候的表現。
如果是上面介紹的流體特性div
, 當其和浮動元素當兄弟的時候,是覆蓋的關係(可以腦補下文字環繞圖片效果)。但是,元素BFC化後,本着“裏面驚天抱詐(和諧)炸成鬼,外面依然泰然釣大魚”的原則,自然是不會與浮動重疊的(你想啊,要是出來個clear:both
還不跟外面浮動幹上一架啊),因此,塊狀相鄰,點擊下面按鈕感受下。
會發現,普通流體元素BFC後,爲了和浮動元素不產生任何交集,順着浮動邊緣形成自己的封閉上下文。如下截圖:
同時,元素原本的流體特性依然保留了。哈,這個很重要,也就是,雖然不與浮動交集,自動退避浮動元素寬度的距離,但,本身作爲普通元素的流動性依然存在,反映在佈局上就是自動填滿除去浮動內容以外的剩餘空間。喲,這不就是自適應佈局嘛!!
2. BFC自適應佈局模塊間的間距
然而,模塊過於親密接觸,可能不是我們想要的。一般而言,我們需要一點間距。
說到間距,我們的第一反應就是margin
. 於是,我們給BFC元素增加一個margin-left:20px
,
CSS代碼如下:
.float-left {
float: left;
}
.follow-content {
margin-left: 20px;
background-color: #cad5eb;
overflow: hidden;
}
結果……納尼~ 怎麼還是像狗屁膏藥貼在一起啊??
您可以狠狠地點擊這裏:BFC元素增加一個margin無效demo
實際上,這裏的margin並不是無效,而是值不夠大,鞭長莫及啊!
用一個形象的Gif表示就是下面這樣:
左側浮動的圖片就好比上面Gif圖片中男孩的胳膊,妹子就是BFC元素,結果兩人緊密接觸。然後,margin-left
就是妹子的胳膊個腳,雖然也甩出去了,可惜長度有限,於是,毫無影響。
如果按照上面的解釋,那我們把margin-left:20px
改成margin-left:150px
就應該有間距了? 一試便知!
.float-left {
float: left;
}
.follow-content {
margin-left: 150px;
background-color: #cad5eb;
overflow: hidden;
}
結果,噹噹噹當:
注意:我這裏舉margin
這個例子,不是讓大家這樣使用,只是爲了讓大家可以深入理解BFC元素與浮動元素混排的特性表現。實際開發,我們完全沒有必要對BFC元素設置margin
,
因爲又回到了流體佈局,明明是固定的15像素間距,但是,每個佈局都要寫一個不同的margin
值,完全沒有重用價值。
但是,間距部分的高潮來了!
我們可以使用浮動元素的margin-right
或者padding-right
輕鬆實現間距效果。間距是20
像素,直接:
.float-left {
float: left;
margin-right: 20px;
}
與浮動元素的寬度是多少沒有任何關係。不僅如此,我們還可以使用BFC元素的padding-left
撐開間距(雖然margin-left
作用雞肋)。
於是,我們可能就會有:
.l { float: left; } .ovh { overflow: hidden; }
的自適應固定搭配。再配合zxx.lib.cssCSS樣式庫的margin
和padding
家族,快速佈局可謂所向披靡。
3. 與純流體特性佈局的優勢
BFC自適應佈局優勢我總結了下面2點:
- 自適應內容由於封閉,更健壯,容錯性強。比方說,內部
clear:both
不會與兄弟float
產生矛盾。而純流體佈局,clear:both
會讓後面內容無法和float
元素在一個水平上,產生布局問題。 - 自適應內容自動填滿浮動以爲區域,無需關心浮動元素寬度,可以整站大規模應用。而純流體佈局,需要大小不確定的
margin
/padding
等值撐開合適間距,無法CSS組件化。
如下效果,圖片能大能小,佈局依然良好:
而CSS代碼就是非常簡單的:
.float-left { float: left; margin-right: 20px; } .bfc-content { overflow: hidden; background-color: #beceeb; }
可以說,有了BFC自適應佈局,基本上沒有了純流體特性佈局存在的價值。然而,只是理論上如此。如果,BFC自適應佈局真那麼吊炸天,那爲何並沒有口口相傳呢?
那我們就得進一步深入理解了。
4. BFC元素家族與自適應佈局面面觀
理論上,任何BFC元素和浮動搞基的時候,都可以實現自動填充的自適應佈局。
但是,由於絕大多數的觸發BFC的屬性自身有一些古怪的特性,所以,實際操作的時候,能兼顧流體特性和BFC特性來實現無敵自適應佈局的屬性並不多。下面我們牽驢遛馬一個一個瞅瞅(類似行爲僅出1個代表示意,你懂的,如float:left/right
):
- float:left 浮動元素本身BFC化,然而浮動元素有破壞性和包裹性,失去了元素本身的流體自適應性,因此,無法用來實現自動填滿容器的自適應佈局。不過,其因兼容性還算良好,與堆積木這種現實認知匹配,上手簡單,因此在舊時代被大肆使用,也就是常說的“浮動佈局”,也算陰差陽錯開創了自己的一套佈局。
- position:absolute 這個脫離文檔流有些嚴重,過於清高,不跟普通小夥伴玩耍,我就不說什麼了……
- overflow:hidden 這個超棒的哦!不像浮動和絕對定位,玩得有點過。也就是溢出剪裁什麼的,本身還是個很普通的元素。因此,塊狀元素的流體特性保存相當完好,附上BFC的獨立區域特性,可謂如虎添翼,宇宙無敵!哈無誒瓦(However), 就跟清除浮動:
.clearfix { overflow: hidden; _zoom: 1; }
一樣。由於很多場景我們是不能
overflow:hidden
的,因此,無法作爲一個通用CSS類整站大規模使用。因此,float+overflow
的自適應佈局,我們可以在局部(你確定不會有什麼被剪裁的情況下)很happy地使用。 - display:inline-block CSS屆最偉大的聲明之一,但是,在這裏,就有些捉襟見肘了。
display:inline-block
會讓元素尺寸包裹收縮,完全就不是我們想要的block
水平的流動特性。唉,只能是一聲嘆氣一槍斃掉的命!然而,峯迴路轉,世事難料。大家應該知道,IE6/IE7瀏覽器下,block
水平的元素設置display:inline-block
元素還是block
水平,也就是還是會自適應容器的可用寬度顯示。於是,我們就陰差陽錯得到一個比overflow:hidden
更牛逼的聲明,即BFC特性加身,又流體特性保留。.float-left { float: left; } .bfc-content { display: inline-block; }
當然,
*zoom: 1
也是類似效果,不過只適用於低級的IE瀏覽器,如IE7~ - display:table-cell 讓元素表現得像單元格一樣,IE8+以上瀏覽器才支持。跟
display:inline-block
一樣,會跟隨內部元素的寬度顯示,看樣子也是不合適的命。但是,單元格有個非常神奇的特性,就是你寬度值設置地再大,大到西伯利亞,實際寬度也不會超過表格容器的寬度。因此,如果我們把
display:table-cell
這個BFC元素寬度設置很大,比方說3000像素。那其實就跟block
水平元素自動適應容器空間效果一模一樣了。除非你的容器寬度超過3000像素,實際上,一般web頁面不會有3000像素寬的模塊的。所以,要是你實在不放心,設個9999
像素值好了!.float-left { float: left; } .bfc-content { display: table-cell; width: 9999px; }
看上去,好像還不錯。但是,還是有兩點制約,一是IE8+以上瀏覽器兼容,有些苦逼的團隊還要管IE6;二是應付連續英文字符換行有些吃力(可以嵌套
table-layout:fixed
解決)。但是,總體來看,適用的場景要比overflow:hidden
廣博很多。 - display:table-row 對
width
無感,無法自適應剩餘容器空間。 - display:table-caption 一無是處……還有其他聲明也都是一無是處,我就不全部展開了……
總結:我們對BFC聲明家族大致過了一遍,能擔任自適應佈局重任的也就是:
overflow:auto/hidden
IE7+display:inline-block
IE6/IE7display:table-cell
IE8+
由於overflow有剪裁和出現滾動條等隱患,不適合作爲整站通用類,於是,最後,類似清除浮動的通用類語句:
.clearfix { *zoom: 1; } .clearfix:after { content: ''; display: table; clear: both; }
兩欄或多欄自適應佈局的通用類語句是(block
水平標籤,需配合浮動):
.cell { display: table-cell; width: 9999px; *display: inline-block; *width: auto; }
這就是zxx.lib.cssCSS樣式庫中.cell
的由來!
當然,由於和浮動元素合作,清除浮動還是要的,於是,就有了.fix
+ .l/.r
+ .cell
的無敵組合,可以多欄,也可以無限嵌套。
如果是局部,且確認安全;或有連續英文字符換行的隱患,你也可以使用.fix
+ .l/.r
+ .ovh
的無敵組合,可以多欄,也可以無限嵌套。
四、結束之言
估計本文是春節前的最後一篇文章了,小生在這裏提前祝大家「羊年快樂」「萬事如意」「事業蒸蒸日上」!
另,本文內容非權威,多個人理解與感悟,僅供參考。歡迎交流,提出您的真知灼見!
感謝閱讀!
本文爲原創文章,會經常更新知識點以及修正一些錯誤,因此轉載請保留原出處,方便溯源,避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
本文地址:http://www.zhangxinxu.com/wordpress/?p=4588