這可能是史上最全的CSS自適應布局總結
這可能是史上最全的CSS自適應布局總結教程 - 茄果 - 博客園
作者:茄果
標題嚴格遵守了新廣告法,你再不爽,我也沒犯法呀!屁話不多說,直入!
所謂布局,其實包含兩個含義:尺寸與定位。也就是說,所有與尺寸和定位相關的屬性,都可以用來布局。
大體上,布局中會用到的有:尺寸相關的盒子模型,普通流、浮動、絕對定位三種定位機制,CSS3中的transform、彈性盒子模塊、試驗中的grid模塊。逛園子的時候經常可以看到浮動布局,inline-block布局,彈性盒布局這幾個名詞。現在對布局也算有一點了解,做個總結鞏固一下。如果你也看了很多資料,但是實際動手時對布局還是無從下手的話,希望本文可以幫你理清思路。
嘮叨一句:看到一個效果圖的時候,千萬不要急著手賤去敲代碼!先思考清楚頁面的構造,理清各元素之間的關係,特別需要注意的是在不同的設備下需要有怎樣的展現,當你思路清晰找到最好的布局方案時,coding其實真的不需要多少時間。
尺寸相關
為什麼要先說尺寸呢?因為尺寸在布局中的作用非常核心,布局方式定位這些只是改變了元素之間的關係,沒有尺寸就什麼也不是。比如我們通常會用margin來控制跟其他元素的距離,這就是布局。
很多人都會覺得,什麼width、margin太簡單了,早就掌握了。這種心態我一開始學習CSS的時候也有,覺得很好理解很簡單,但是後面才發現自己原來很多東西都沒真正掌握。看看張鑫旭大神給我們上的政治課:說說CSS學習中的瓶頸 " 張鑫旭-鑫空間-鑫生活
先說說百分比,百分比是相對父對象的,這裡特性非常好用,很多時候會用在自適應布局上面。瀏覽器尺寸的改變,就是根節點html的長寬改變,我們可以用%來將瀏覽器尺寸和元素尺寸聯繫起來,做到自適應。
另外一個比較有意思的是auto,auto是很多尺寸值的默認值,也就是由瀏覽器自動計算。首先是塊級元素水平方向的auto,塊級元素的margin、border、padding以及content寬度之和等於父元素width。使用auto屬性在父元素寬度變化的時候,該元素的寬度也會隨之變化。
但是當該元素被設為浮動時,該元素的width就變成了內容的寬度了,由內容撐開,也就是所謂的有了包裹性。overflow | position:absolute | float:left/right都可以產生包裹性,替換元素也同樣具有包裹性。在具有包裹性的元素上想利用width : auto;來讓元素寬度自適應瀏覽器寬是不行的。
高度方向:外邊距重疊,外邊距auto為0,這兩點需要注意。書寫方向什麼的,接觸比較少就不扯了。
那為什麼margin:auto對不能計算垂直方向的值呢?很簡單,垂直方向是被設計成可以無限擴展的,內容越多瀏覽器便產生滾動條來擴展,所以垂直方向都找不到一個計算基準,以此返回一個false,便成了0。
用處:通過width、height控制大小,各個方向的margin值控制與邊界或者其他元素的距離來定位。
浮動
目前PC網站大多使用float布局,從成本上考慮大改的概率很小,所以不要說浮動無用,總是會有機會讓你維護的!代表網站:淘寶、騰訊、百度,好吧BAT都到齊了。
浮動聽得多了,博客園上關於用浮動布局的介紹也非常的多。浮動原本用於文本環繞,但卻在布局被發揚光大,這就是命!我的理解:浮動布局的核心就是讓元素脫離普通流,然後使用width/height,margin/padding將元素定位。脫離普通流的元素,就像脫離地心引力一樣,與普通流不在一個高度上。這個跟圖層的概念類似。高度不同所以可以疊在其他元素上面產生重疊或者使用負邊距跑到父元素外,理解了這一點浮動布局就很好理解了。
下面用個聖杯布局的例子說明一下,理解了這個之後其他布局更加簡單:
left,寬度固定,高度可固定也可由內容撐開
right,寬度固定,高度可固定也可由內容撐開
center,可以自適應瀏覽器寬度,高度可固定也可由內容撐開。
HTML & CSS:
原理非常簡單,左右側邊欄定寬並浮動,中部內容區放最後不浮動、默認width:auto並設置相應外邊距,讓左右側邊欄浮動到上面。注意:子元素設置為浮動之後,父對象的高度就坍塌了,需要設置父對象後的元素清除浮動,這樣父對象的高度才能被浮動子元素撐起來了。
當然,我們也要問一下,為啥父對象高度會坍塌呢?上面也說過了,浮動元素已經脫離了普通流,父對象所在的普通流比喻成地表,那浮動元素就已經上天了。但是父對象還在地表啊,從外太空看浮動元素在父對象裡面,但是其實並不在,又怎麼能撐開父對象呢?寬度如果我們不設置的話,其實也是為0的,因為父對象裡面空空如也,所以寬高為0。
要撐開的辦法就兩個,1是讓父對象也上天(。。。你咋不上天呢),2是把浮動元素的邊框邊界拉下來。
父對象也上天(即浮動)的話,那就不能實現寬度自適應了。因為float元素的width:auto是包裹內容的,參考前面說的!
辦法2就是在後面的元素里加一個clear語句。說到這個問題就要扯到clear與BFC了,我就不獻醜了。傳送門:clear
這個三列布局還有個雙飛(是雙飛翼!想啥呢)的變種,就是在HTML中center部分也就是內容區提到最前面,也就是內容先行渲染。在網路不好的時候,左右雙翼能不能出來不要緊,先讓主體內容出來!這種想法,明顯的優秀工程師思維,但,尼瑪的雙翼都是廣告啊。廣告不出來,哪能賺錢養你們這群工程師?所以提出雙飛的玉伯才離開了淘寶???(純屬意淫,如真屬實,當我扯淡,哈哈哈!)
先上碼:
思路:
1)既然HTML裡面要讓center放前面,為了讓left跑到center前面,那center也必須浮動了,否則因為都是塊元素他們會分兩行。
2)浮動之後還要讓center寬度自適應,那明顯width只能100%,然後在父元素中設width:auto,還有兩側margin,其實也就是父對象寬度自適應,center只是繼承content的寬度。
3)對left使用負的margin讓他們浮動到上方去。
代碼裡面我用到了一個calc(),這個CSS3帶來的計算函數簡直酷斃了!本例里如果不使用calc函數,那麼就需要wrap左邊距為0,left左邊距-100%,然後center多加一層子塊DIV設置margin-left:100px,可以達到同樣的效果!calc函數與百分比配合就足以實現自適應的要求!目前所有的自適應布局都在利用瀏覽器來為我們計算尺寸,但是有了calc之後我們就可以自己制定規則!單是想想都高潮了吧?
總結:使用浮動來進行布局,一個比較大的問題是清除浮動。這個可以使用一個after偽類來清除。更大的問題是浮動性像水一樣向上流動,難以把握。在元素較多而且元素高度尺寸不一的情況下,單純使用浮動只能實現上端對齊,這對於適應多種設備的布局就顯得力不從心了。目前的做法是犧牲一部分內容,將元素做成等高排列,從美觀上看也當然也是極好的,比參差不齊的排列要美觀。
普通流布局
普通流布局:display : inline-block!這是一個傳說中取代float布局的存在。看了一些網站,PC端浮動為主,移動端的也用的不多啊,已經有些使用flex的了,說好的inline-block一統江湖呢?
使用inline-block之前先處理點小障礙:inline-block元素會有4px左右的空隙,這個是因為我們寫代碼時候的換行符所致。
解決辦法很簡單:在inline-block的父元素中設置樣式font-size:0;letter-spacing: -4px; 然後設置inline-block的所有兄弟元素 font-size:值;letter-spacing: 值px; 恢復正常的顯示。
另外還有一點需要注意的是inline-block默認是基線對齊的,而inline-block的基線又跟文本基線一致,所以在內容不同的時候並不能水平對齊。只需要用vertical-align顯式聲明一下top/bottom/middle對齊即可。這裡補充一下基線的內容,沒你想的那麼簡單哦。分有文字和無文字兩種情況:
1)無文字:容器的margin-bottom下邊緣。與容器內部的元素沒一毛錢關係。
2)有文字:最後一行文字的下邊緣,跟文字塊(p,h等)的margin、padding沒關係!注意是最後一行,無論文字在什麼子對象容器內在什麼位置都沒關係,瀏覽器會找到最後一行文字對齊底部。
你們感受一下:
警示:inline-block的基線是最後一行文字的底部,flex裡面的基線是第一行文字的底部(請看下文阮老師的文章)
滿滿的都是淚啊。。。既然都叫baseline,何必呢?
使用inline-block進行聖杯布局:
這裡也沒什麼好說的,用到的也是width:auto和width:100%這兩點,簡單知識點的簡單用法。
雙飛的話,代碼跟聖杯的基本相同,注意在html的順序變為center>right>left,只改左欄移動的margin-left: calc(-100% – 100px)到預定位置即可。不能用calc的話可以在center裡面再加一層,跟浮動一樣的處理方式。更簡單的方法是使用CSS3帶給我們的box-sizing屬性。請看代碼:
總結:相比浮動inline-block更加容易理解,也更符合我們的認知,結合盒子模型的幾個控制屬性就可以進行布局了。對於元素高度不同的情況,目前浮動布局的做法都是將元素做成等高元素進行展現,這從美學上看也符合整齊的要求,不過犧牲了一部分內容。但inline-block有vertical-align屬性,可以很好地解決元素高度不同而帶來的布局問題。用過之後,你也會喜歡上inline-block的。。。至少我會!
絕對定位
前面的浮動和普通流中其實定位都是靠盒子模型控制的,與我們常說的定位還是有差別的。而絕對定位就是我們平常所說的定位,給定參考坐標系+坐標確定位置。關於絕對定位的資料太多,我就不說了。提一點就是absolute定位的基準是最近的非static定位父對象,而fixed是相對html根節點的定位。兩種定位都會脫離普通流,跟之前說的浮動一樣,上天了。
當然,他們跟浮動在空間中的位置還是有差別的,項目中有遇到這個問題的請參考張大嬸的文章: 深入理解CSS中的層疊上下文和層疊順序 " 張鑫旭-鑫空間-鑫生活 還是要結合項目來看,否則看過也只是看過而已,並不會存到你的腦子裡,畢竟還是相當抽象相當理論性的東西。借用張大神的一個總結圖:
使用絕對定位(特指absolute)做自適應布局跟前面兩種方式沒太大差別,寬度自適應還是在auto和100%上做文章,而位置則由top/bottom/left/right等控制。還是以聖杯布局來舉例:
<!DOCTYPE html>n<html>n <head>n <meta charset="utf-8" />n <title>寬度自適應布局</title>n <style>n .wrap {n position: relative;n background-color: #FBD570;n margin-left: 100px;n margin-right: 150px;n height: 250px;n }n .left {n position: absolute;n top: 0;n left: -100px;n width: 100px;n background: #00f;n height: 180px;n }n .right {n position: absolute;n top: 0;n right: 0;n width: 150px;n background: #0f0;n height: 200px;n margin-right: -150px;n }n .center {n position: absolute;n top: 0;n left: 0;n background: #B373DA;n height: 150px;n min-width: 150px;n width: 100%;n }n </style>n </head>n <body>n <div class="wrap">n <div class="center">n center,可以自適應瀏覽器寬度,高度固定。n </div>n <div class="left">left,寬度高度固定</div>n <div class="right">right,寬度高度固定</div>n </div>n </body>n</html>n
父元素為relative,子元素為absolute,這樣的話,又會出現跟浮動一樣的問題:父對象高度坍塌,子元素不能撐起父對象。原因也跟浮動一樣,解決辦法的話目前我知道的只有給父對象指定一個確定height值,大家如果有更好的辦法,請聯繫我!
總結:單純使用絕對定位進行自適應布局的情況很少,一般絕對定位都用在尺寸固定的元素定位上。而且fixed定位的渲染效率很低,因為它會頻繁觸發瀏覽器的重排。另外提一點:CSS3的transform會對絕對定位產生影響哦~比如說讓fixed定位不再固定在瀏覽器視窗的黑魔法:CSS3 transform對普通元素的N多渲染影響
彈性盒子
CSS3中對布局影響最大的莫過於彈性盒子模塊了,這是一套區別於以往盒子模型布局的全新方案。上面幾種方法你可以看到,為了實現自適應我們用的都是width:auto和100%的嵌套以及各種邊距的移動定位,這套規則並不符合我們的認知。為什麼不能開拓出一塊區域,橫豎排列都可以,內部所有元素的尺寸可以按照一個規則和這個區域的大小聯繫起來?終於CSS3做出了改變,引入了flex彈性布局方案,彈性盒布局有如下優勢:
1.獨立的高度控制與對齊。
2.獨立的元素順序。
3.指定元素之間的關係。
4.靈活的尺寸與對齊方式。
在MDN上有非常簡單易懂的基礎教程:使用 CSS 彈性盒子
上面也已經給出了聖杯布局的自適應布局方案,所以代碼就不貼了不過這個例子實現的是3欄成比例縮放,左右欄如果需要固定值的話可以寫成 flex: 0 0 150px; 的樣式。
但是上面的教程沒有給出各個屬性的詳細解釋,建議看看阮一峰的博文,詳細易懂而且配圖超漂亮的有木有:Flex 布局教程:語法篇 - 阮一峰的網路日誌
總結:彈性盒子在移動端的應用會越來越普遍,這套模型值得去好好研究。語法規則都是非常貼近人性,非常靈活,瀏覽器兼容性也非常好,當然國內百花齊放的移動瀏覽器會有哪些大坑呢?我們拭目以待~
其他
其他包括position:relative和CSS3中的transform都可以實現定位,但是由於他們在原來的普通流中還佔著一個坑,所以很少用來布局啥的。transform是個很酷炫的東西,可以用平面的素材做出很多3D的效果,而且不需要js就可以做,非常好玩。此文已經很長,就不多說了,以後會寫一篇文章來專門說說她的故事。
閱讀原文
推薦閱讀: