CSS佈局在前端開發中像呼吸同樣——再日常不過的事。好比同事A在嚐到了Flexbox佈局的甜頭以後,任何佈局都會以display:flex
打頭陣,同事B由於項目得支持IE10,像避開毒蛇同樣的避開Flexbox佈局方法。你會發現我可能有點嗤笑這樣的行爲,我曾經也是這樣的一員,我想爲這個問題——當遇到css佈局,你在考慮什麼? 整理一個完整的解決方案。javascript
你在考慮什麼:從什麼樣的HTML結構出發可以幫助到css佈局?你的佈局方法武器庫都有什麼,在具體場景下,選擇什麼合適的佈局方法?須要作支持舊瀏覽器嗎?Flexbox、Grid這些佈局的方法弄潮兒在舊瀏覽器中的最佳實踐是?等等等等。css
本文將介紹個人"答案",歡迎胖友們補充、更正。html
Normal flow(不知什麼中文翻譯妥帖,仍是扔了英文...)指的是若是沒有改變css佈局代碼,網頁中標籤的默認表現方式。好比demo-normal-flow:塊級標籤p
挨個從上往下,而內聯標籤span
表現得像段落中的文本。前端
當咱們建立、自定義一個佈局,實際上是調整標籤在Normal flow中的位置,或是直接從Normal flow移除,咱們最最原始的材料就是Normal flow。若是使用語義化標籤(semantic markup),從一個結構良好的HTML文檔開始是頗有幫助的:java
HTML5新加了些幫助結構化的標籤,html-document-structured 這篇文章能夠參考,這裏作一個overview:git
header
:body
、main
標籤的直接子標籤,位置在頁面頭部,內容可能爲logo、標語、搜索提示、導航欄;nav
:導航欄包在nav
標籤內,可能出如今頭部、側邊欄、底部等等,這裏有個demo-mdn-nav,神奇的地方在於設置nav
標籤的display:inline-block
,是做用在li
標籤上的;main
:body
標籤的直接子標籤,主內容區域;aside
:側邊欄;article
:通常出如今main
標籤內,article
標籤內能夠有section
、footer
等標籤,是比較獨立的內容,好比像博客網站主頁的一個文章簡介;section
:section
和div
很相似,若是使用div
標籤是爲了對內容作樣式控制,或者爲了便於javascript獲取作其餘操做,那麼使用div
就是你的答案,其餘狀況就用section
;address
:提供聯繫信息,放在article
標籤內提供文章做者信息,放在main
、body
、footer
內提供網站信息;footer
:通常在HTML結構底部,補充網站信息,若是放在article
內補充文章信息; Normal flow是CSS佈局的起點,更好的選擇是語義化標籤(semantic markup)做爲CSS佈局的起點。github
css佈局方法有不少,如Flexbox、Grid、Float等等等等,在使用以前得把握兩個中心思想:web
接下來主要以講demo的形式介紹各個佈局方法的使用場景,對於佈局方法自身如何使用不會過多說明。瀏覽器
Flexbox是Flexible Box Layout的簡稱,Flexbox既能夠用於整個頁面的佈局,也能夠用於局部部件的佈局。Flexbox存在些瀏覽器兼容性的問題,在舊瀏覽器中的實踐會在以後說明。接下來幾個場景是創建在瀏覽器支持Flexbox的前提下。服務器
Flexbox全稱Flexible Box Layout中的Flexible(靈活性),是它的立命之本。Flexbox的第一個使用場景也呼之欲出——Flexing sizing of flex items,也就是盒子尺寸的高度靈活性:
section
標籤是Flex容器,article
標籤是Flex item,其中前面兩個article
標籤flex:1 200px
,最後一個article
標籤flex:2 200px
。具體表現爲,若是不能提供3個Flex item都是200px
寬度的空間,則它們仨寬度一致,若是能提供,剩餘空間按照1:1:2分配;footer
標籤高度固定,section
標籤由於flex:1
而佔據餘下全部空間。在水平方向,也能夠是側邊欄寬度固定,主要內容佔據餘下全部空間;Flexbox提供像align-items
、justify-content
這樣的屬性去調整flex items在主軸(main axis)、副軸(cross axis)的位置。好比最多見的考試題,水平垂直居中某個元素,demo-flexbox-alignment ;再好比justify-content:space-around
做用於導航條的樣式,demo-flexbox-alignment-justify-content。
通常來講,標籤出現順序由源代碼中出現順序決定,Flexbox爲Flex items提供了order
屬性,提供從css角度調整Flex items在頁面中出現的順序的能力。
若是爲Flex item設置主軸方向(main axis)的margin
值爲auto
,好比主軸是橫向的,設置margin-left:auto
,這個Flex item會佔據往左這個方向的剩餘空間:demo-flex-flex-item-margin:auto。
Grid佈局,和Flexbox設計爲在一個方向佈局不一樣,它幫助咱們更加容易地從兩個方向上佈局元素。我更加推薦Grid佈局應用於整個頁面,由於它很是清爽、優雅。它一樣存在瀏覽器兼容問題,且比Flexbox更要重,在舊瀏覽器中的實踐會在以後說明。接下來幾個場景是創建在瀏覽器支持Grid的前提下。
爲何說它優雅呢?看幾個demo就知道了。
demo-grid-layout、demo-grid-layout-grid-template-areas:兩個demo都實現了最基本的一個頁面狀況,一個頭部、一個側邊欄、一個主要內容區域、一個底部,前者是Grid佈局最常規的使用,後者使用了grid-template-areas
屬性;
另外在Grid佈局以前,有一些庫在作模擬Grid System的工做,將一個頁面分紅6列或者12列,標籤按列去佔據頁面。Grid佈局方法徹底有這樣一個能力,使用12列布局的Grid重寫前面兩個demo實現的效果:demo-grid "framework";
若是能使用Grid佈局整個頁面,我是強烈推薦的,它的思惟切入點再也不是一維,而是二維,這是一場變革。
Floats佈局方法既能夠針對整個頁面,也能夠針對局部部件,雖然設計之初並非爲了佈局整個頁面。我是把Floats做爲沒法使用Grid、Flexbox時候的第一選擇。像前面提到的作Grid System的css庫,它其實也是將其中的每個item設置爲了float:left
,而後計算佔據寬度的百分比以模擬Grid System。
另外,"floated item"(設置float:left
或float:right
)會從Normal flow中移除。來看看具體應用的demo吧。
「文字環繞圖片」是Floats設計的初衷:demo-float-avatar image
demo-float-a fun drop-cap effect
"Floated item"的高度是不包括在容器標籤內,若是高度超出容器標籤,會出現顯示上的錯誤,這是Floats應用於頁面佈局最多見的一個問題:demo-float-floated items overflow the wrapper
解決方案有三種:
::after
清除浮動,或者在容器標籤內加一個空的div
元素清除浮動也能夠解決問題;overflow
屬性創建一個BFC,可是當心overflow:hidden
、overflow:auto
可能增長了你不須要的顯示效果;display:flow-root
創建一個BFC,並且不會像overflow
增長不須要的顯示效果,可是得考慮瀏覽器支不支持這個屬性;在許多年之前,web開發者使用table
標籤作整個頁面的佈局,將頁面內容放入table
的行和列中,這種方法的問題在於不靈活,並且語義錯誤(對於屏幕閱讀器的用戶很不友好)。之因此放入table
標籤能佈局,是由於存在描述table layout的一些列css屬性,它們是和table
這些標籤是綁定的。而直接使用這些css屬性,用於不是table
這些元素佈局,這種方法被稱爲是 "using CSS tables" :demo-using css tables;
"using css tables" 被稱做是一種遺留方法(legacy method),用於整個頁面佈局,適用於不支持Flexbox和Grid的瀏覽器,可是我這裏的最佳替補仍是Floats。
Positioning的定位和前面四種不太同樣,它通常不用於建立整個頁面佈局,而是管理和微調標籤,作一個局部位置的調整。要注意若是已經設置如下幾個position
屬性值的標籤,層級是高於Normal flow,層級可經過z-index
屬性調整。
position:relative
相對定位,作位置調整demo-positioning-relative-left/right:這個例子不是很深動形象,可是demo糙理不糙,確實是經過設置left
、top
等屬性值去移動位置。
posision:absolute
絕對定位,作任何可彈出、可拖拽UI部件MDN上放了這樣一個使用場景說明:
popup information boxes and control menus; rollover panels; UI features that can be dragged and dropped anywhere on the page; and so on...
postion:fixed
固定定位demo-position-fixed:固定表頭,表頭位置始終定於頁面頂部,不隨滾動條滾動而滾動。
固然可用於任何須要固定於頁面某個位置的UI部件。
position:sticky
粘性定位這裏有個很經典的例子: demo-sticky-a scrolling index page where different headings stick to the top of the page as they reach it ;可是在使用時得考慮瀏覽器兼容問題,兼容性目前堪憂。
Multicol是Multi-columns layout的簡稱,它提供了一種在列中佈置內容的方法,相似於文本在報紙中的流動方式,使得閱讀更加友好,不用上下滾動。Multicol的定位是這一種特殊的內容展現佈局。
demo-multi-column layout:經過在container
塊級元素上設置column-count
或者column-width
屬性開啓Multicol:
最初吸引我作這個話題的緣由,是目前公司項目得支持IE十、IE11,現狀是項目中的佈局方法沒有Grid、鮮有Flexbox,就比較心癢癢,想搞搞明白到底能不能在支持IE十、IE11的狀況使用這兩種潮流的佈局方法。因此在舊瀏覽器中的實踐重點考慮的是IE十、IE11兩位。
瀏覽器對Flexbox的支持仍是挺不錯的,IE10支持2012版語法,IE11支持的語法和現代瀏覽器一毛同樣。在IE10和IE11中使用Flexbox存在一些已知的問題,在caniuse-flexbox有說明,同時還有一個Flexbugs是一個問題的列表以及解決措施。
因此這裏的最佳實踐分兩步:
另外貼兩篇Postcss掃盲文章:Some things you may think about PostCSS... and you might be wrong、It's Time for Everyone to Learn About PostCSSWhat It Really Is; What It Really Does
瀏覽器對Grid的支持較Flexbox要差不少,IE十、IE11支持的是舊版本的規範,是帶有-ms-
前綴,但即便使用autoprefixer補上了前綴,相同屬性名相同屬性值在頁面中的表現也可能不一致。這樣我是不推薦Flexbox實踐中的方法,而是使用Feature Queries。
Feature Queries是使用css的@supports
,@supports
用於檢測瀏覽器是否支持參數中的屬性屬性值,若是支持則渲染花括號中的css代碼,相似於:
@supports (display: grid) {
// code that will only run if CSS Grid is supported by the browser
}
複製代碼
這裏有個細節點,IE十、IE11是不支持@supports
規則,因此壓根不會進入這個條件判斷,花括號中的css代碼是不會渲染的,這與咱們考慮的邏輯:支持@supports
規則、不支持display:grid
是不一樣的,可是最後的結果是同樣的。
以一個例子講述一下整個流程:demo-creating fallbacks in CSS
.wrapper{
overflow:auto;
}
.item {
float:left;
width:33.3%;
}
複製代碼
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
複製代碼
由於舊瀏覽器不支持Grid佈局,Grid相關屬性舊瀏覽器都沒法解釋。在支持的瀏覽器中使得item由floated item轉爲grid item,這樣的覆蓋行爲由css規定,更多覆蓋狀況見Fallback method。另外一部分是直接放入對舊瀏覽器是有影響的,要作Feature queries:
@supports (display: grid) {
.item {
width: auto;
}
}
複製代碼
覆蓋原有的width:33.3%
。
沒錯,這裏的實踐得寫兩套樣式。因此有人提出問題,寫一套支持全部瀏覽器的不就得了,幹嗎非得用Grid?這是個很實際的問題,畢竟寫兩套,再加測試調試,會增長必定工做量。有幾個場景建議使用Grid:
尤爲是支持IE十、IE11的項目,測試是很重要的一個環節,最佳的測試仍是在各個瀏覽器中打開。但這裏存在獲取瀏覽器的問題,例如win10系統上僅有IE11,而不能使用IE10等。有些公司有本身的服務器,有各類瀏覽器可供測試;若是沒有的話,能夠考慮下載虛擬機:download the Virtual Machines offered by Microsoft ,或者使用像 BrowserStack 訪問遠程的虛擬機。
從開發者角度,整個工做流程應該是這樣子:
CSS Grid Layout and Progressive Enhancement
Using CSS Grid: Supporting Browsers Without Grid
Some things you may think about PostCSS... and you might be wrong
It's Time for Everyone to Learn About PostCSSWhat It Really Is; What It Really Does