當遇到css佈局,你在考慮什麼?

​ CSS佈局在前端開發中像呼吸同樣——再日常不過的事。好比同事A在嚐到了Flexbox佈局的甜頭以後,任何佈局都會以display:flex打頭陣,同事B由於項目得支持IE10,像避開毒蛇同樣的避開Flexbox佈局方法。你會發現我可能有點嗤笑這樣的行爲,我曾經也是這樣的一員,我想爲這個問題——當遇到css佈局,你在考慮什麼? 整理一個完整的解決方案。javascript

​ 你在考慮什麼:從什麼樣的HTML結構出發可以幫助到css佈局?你的佈局方法武器庫都有什麼,在具體場景下,選擇什麼合適的佈局方法?須要作支持舊瀏覽器嗎?Flexbox、Grid這些佈局的方法弄潮兒在舊瀏覽器中的最佳實踐是?等等等等。css

​ 本文將介紹個人"答案",歡迎胖友們補充、更正。html

Normal flow:css佈局的起點

​ Normal flow(不知什麼中文翻譯妥帖,仍是扔了英文...)指的是若是沒有改變css佈局代碼,網頁中標籤的默認表現方式。好比demo-normal-flow:塊級標籤p挨個從上往下,而內聯標籤span表現得像段落中的文本。前端

​ 當咱們建立、自定義一個佈局,實際上是調整標籤在Normal flow中的位置,或是直接從Normal flow移除,咱們最最原始的材料就是Normal flow。若是使用語義化標籤(semantic markup),從一個結構良好的HTML文檔開始是頗有幫助的:java

  1. 語義化標籤確保**內容可讀,**即便是很是受限制的瀏覽器、像屏幕閱讀器這樣的設備也如此;
  2. 以此爲起點去佈局文檔,是合做友好的,而不是破壞性的、改動很大的,由於大多數標籤仍是在Normal flow中;

HTML5新加了些幫助結構化的標籤,html-document-structured 這篇文章能夠參考,這裏作一個overview:git

  • headerbodymain標籤的直接子標籤,位置在頁面頭部,內容可能爲logo、標語、搜索提示、導航欄;
  • nav:導航欄包在nav標籤內,可能出如今頭部、側邊欄、底部等等,這裏有個demo-mdn-nav,神奇的地方在於設置nav標籤的display:inline-block,是做用在li標籤上的;
  • mainbody標籤的直接子標籤,主內容區域;
  • aside:側邊欄;
  • article:通常出如今main標籤內,article標籤內能夠有sectionfooter等標籤,是比較獨立的內容,好比像博客網站主頁的一個文章簡介;
  • sectionsectiondiv很相似,若是使用div標籤是爲了對內容作樣式控制,或者爲了便於javascript獲取作其餘操做,那麼使用div就是你的答案,其餘狀況就用section
  • address:提供聯繫信息,放在article標籤內提供文章做者信息,放在mainbodyfooter內提供網站信息;
  • footer:通常在HTML結構底部,補充網站信息,若是放在article內補充文章信息;

Normal flow是CSS佈局的起點,更好的選擇是語義化標籤(semantic markup)做爲CSS佈局的起點。github

在具體場景下選擇合適的佈局方法

css佈局方法有不少,如Flexbox、Grid、Float等等等等,在使用以前得把握兩個中心思想web

  1. 每種佈局方法有它的使用場景、使用上下文,在具體場景中選擇對應合適的佈局方法纔是王道;
  2. 一個頁面每每會應用多種佈局方法,而不是一種佈局方法解決全部問題,佈局方法間是合做的關係;

接下來主要以講demo的形式介紹各個佈局方法的使用場景,對於佈局方法自身如何使用不會過多說明。瀏覽器

Flexbox

Flexbox是Flexible Box Layout的簡稱,Flexbox既能夠用於整個頁面的佈局,也能夠用於局部部件的佈局。Flexbox存在些瀏覽器兼容性的問題,在舊瀏覽器中的實踐會在以後說明。接下來幾個場景是創建在瀏覽器支持Flexbox的前提下。服務器

Flexing sizing of flex items

Flexbox全稱Flexible Box Layout中的Flexible(靈活性),是它的立命之本。Flexbox的第一個使用場景也呼之欲出——Flexing sizing of flex items,也就是盒子尺寸的高度靈活性:

  1. demo-flexbox-flexsection標籤是Flex容器,article標籤是Flex item,其中前面兩個article標籤flex:1 200px,最後一個article標籤flex:2 200px。具體表現爲,若是不能提供3個Flex item都是200px寬度的空間,則它們仨寬度一致,若是能提供,剩餘空間按照1:1:2分配;

  1. demo-flexbox-flex-fixedWidthWithFlex:這是實際使用中一個很常見的作法,這裏將footer標籤高度固定,section標籤由於flex:1而佔據餘下全部空間。在水平方向,也能夠是側邊欄寬度固定,主要內容佔據餘下全部空間;

水平、垂直位置調整

Flexbox提供像align-itemsjustify-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

Grid佈局,和Flexbox設計爲在一個方向佈局不一樣,它幫助咱們更加容易地從兩個方向上佈局元素。我更加推薦Grid佈局應用於整個頁面,由於它很是清爽、優雅。它一樣存在瀏覽器兼容問題,且比Flexbox更要重,在舊瀏覽器中的實踐會在以後說明。接下來幾個場景是創建在瀏覽器支持Grid的前提下。

優雅的整個頁面佈局

爲何說它優雅呢?看幾個demo就知道了。

demo-grid-layoutdemo-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佈局方法既能夠針對整個頁面,也能夠針對局部部件,雖然設計之初並非爲了佈局整個頁面。我是把Floats做爲沒法使用Grid、Flexbox時候的第一選擇。像前面提到的作Grid System的css庫,它其實也是將其中的每個item設置爲了float:left,而後計算佔據寬度的百分比以模擬Grid System。

另外,"floated item"(設置float:leftfloat:right)會從Normal flow中移除。來看看具體應用的demo吧。

文字環繞圖片

「文字環繞圖片」是Floats設計的初衷:demo-float-avatar image

文本首單詞首字母特殊處理

demo-float-a fun drop-cap effect

頁面佈局:一個最多見Floats問題的解決

"Floated item"的高度是不包括在容器標籤內,若是高度超出容器標籤,會出現顯示上的錯誤,這是Floats應用於頁面佈局最多見的一個問題:demo-float-floated items overflow the wrapper

解決方案有三種:

  1. demo-float-clearfix hack:在容器標籤僞類::after清除浮動,或者在容器標籤內加一個空的div元素清除浮動也能夠解決問題;
  2. demo-float-overflow:使用overflow屬性創建一個BFC,可是當心overflow:hiddenoverflow:auto可能增長了你不須要的顯示效果;
  3. demo-float-display:flow-root:更現代的方法是使用display:flow-root創建一個BFC,並且不會像overflow增長不須要的顯示效果,可是得考慮瀏覽器支不支持這個屬性;

Table layout

在許多年之前,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

Positioning的定位和前面四種不太同樣,它通常不用於建立整個頁面佈局,而是管理和微調標籤,作一個局部位置的調整。要注意若是已經設置如下幾個position屬性值的標籤,層級是高於Normal flow,層級可經過z-index屬性調整。

position:relative 相對定位,作位置調整

demo-positioning-relative-left/right:這個例子不是很深動形象,可是demo糙理不糙,確實是經過設置lefttop等屬性值去移動位置。

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

Multicol是Multi-columns layout的簡稱,它提供了一種在列中佈置內容的方法,相似於文本在報紙中的流動方式,使得閱讀更加友好,不用上下滾動。Multicol的定位是這一種特殊的內容展現佈局。

報紙閱讀模式

demo-multi-column layout:經過在container塊級元素上設置column-count或者column-width屬性開啓Multicol:

Flexbox、Grid考慮支持舊瀏覽的最佳實踐

最初吸引我作這個話題的緣由,是目前公司項目得支持IE十、IE11,現狀是項目中的佈局方法沒有Grid、鮮有Flexbox,就比較心癢癢,想搞搞明白到底能不能在支持IE十、IE11的狀況使用這兩種潮流的佈局方法。因此在舊瀏覽器中的實踐重點考慮的是IE十、IE11兩位。

Flexbox: Postcss插件Autoprefixer

瀏覽器對Flexbox的支持仍是挺不錯的,IE10支持2012版語法,IE11支持的語法和現代瀏覽器一毛同樣。在IE10和IE11中使用Flexbox存在一些已知的問題,在caniuse-flexbox有說明,同時還有一個Flexbugs是一個問題的列表以及解決措施。

因此這裏的最佳實踐分兩步:

  1. 藉助Postcss插件爲咱們自動加上前綴,以支持IE10的2012版語法和現代語法;
  2. 使用過程避開在IE10和IE11中使用Flexbox的已知問題,若是仍是碰到了在舊瀏覽器和現代瀏覽器中表現不一致,去Flexbugs 找找有沒有相同狀況。若是再沒有,再考慮替換方案,也能夠給 Flexbugs 這個項目提issue;

另外貼兩篇Postcss掃盲文章:Some things you may think about PostCSS... and you might be wrongIt's Time for Everyone to Learn About PostCSSWhat It Really Is; What It Really Does

Grid: Feature Queries

瀏覽器對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

  1. 首先是給舊瀏覽器作支持,準備一套Fallback method,保證在全部瀏覽器上都是工做的:
.wrapper{
  overflow:auto;
}

.item {
  float:left;
  width:33.3%;
}
複製代碼
  1. 再給支持Grid的瀏覽器作覆蓋,覆蓋代碼分兩部分,一部分是直接放入對舊瀏覽沒有影響的:
.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:

  1. 項目得支持IE十、IE11等舊瀏覽器,可是開發者想嚐鮮Grid佈局,Feature Queries提供了這樣的能力;
  2. 項目週期會很長,可能如今不支持Grid佈局的瀏覽器,之後就支持了;
  3. 要實現的效果不使用Grid佈局很難實現,且對在舊瀏覽器中訪問效果要求不高,能看就行;

測試

尤爲是支持IE十、IE11的項目,測試是很重要的一個環節,最佳的測試仍是在各個瀏覽器中打開。但這裏存在獲取瀏覽器的問題,例如win10系統上僅有IE11,而不能使用IE10等。有些公司有本身的服務器,有各類瀏覽器可供測試;若是沒有的話,能夠考慮下載虛擬機:download the Virtual Machines offered by Microsoft ,或者使用像 BrowserStack 訪問遠程的虛擬機。

從開發者角度,整個工做流程應該是這樣子:

  1. 初始開發計劃制定
  2. 開發
  3. 測試、發現問題
  4. 修復問題,重複2~4步驟

總結

  1. 作css佈局
    1. 佈局的出發點是語義化標籤
    2. 考慮在具體場景下使用什麼佈局方法最合適最簡單
    3. 考慮要不要支持舊瀏覽器,要明確支持不意味着顯示如出一轍,可存在體驗優秀+體驗通常兩種模式
  2. Flexbox、Grid考慮舊瀏覽器的實踐(支持IE十、IE11)
    1. Flexbox支持性比Grid好,使用Autoprefixer前綴,避開Flexbox bug、已知issues,放開了使用
    2. Grid佈局要想使用,得用Feature Queries的方法,額外準備一套Fallback Methods
    3. Autoprefixer關閉對Grid屬性添加前綴(默認行爲)
  3. 測試
    1. 測試流程:初始開發計劃制定 > 開發 > 測試、發現問題 > 修復問題,重複2~4步驟
    2. 藉助虛擬機等

參考連接

MDN-CSS-layout

html-document-structured

Using Feature Queries in CSS

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

相關文章
相關標籤/搜索