網格布局(CSS Grid Layout)淺談
近幾年,Flexbox的出現,帶來了巨大的轟動效應,它使CSS變得更加強大,給我們帶來了更大的施展空間,并在幾乎所有的瀏覽器中都得到了很好地支持,你沒有理由不使用它。我們發現Flexbox在很多情況下對我們非常有幫助,但是它絕對不是一個構建整個布局的理想候選方案。我們更傾向于使用浮動或者內聯元素來構建整體布局,但是這并不是浮動、內聯元素被創建出來的初衷。但很遺憾CSS從來沒有一個這樣的內置功能,為了建立布局,我們沒有選擇,只能用這些Hack。
好消息是 CSS Grid Layout Model 是一個轉折點,我們可以用它的一些基礎功能就可以重建一些標準布局。目前,瀏覽器對網格布局的支持情況還不是很理想。唯一支持它的瀏覽器是Edage和最新的Internet Explorer 。幸運的是,我們可以在Google Chrome,FireFox ,Safari 上手動啟用該功能,在Chrome上我們在導航欄輸入 chrome://flags 切換到“啟用實驗性Web平臺”標識并重啟瀏覽器,FireFox上我們在導航欄輸入 about:config , 搜索 layout.css.grid.enabled 設置為 true ,Safari上我們需要下載 Safari Technology Preview 版本的瀏覽器,就可以使得瀏覽器支持網格布局。
博客布局的重新設計
博客的布局是我們比較熟知的常用布局之一,有頁眉(header),內容(content),側邊欄(sidebar),和頁尾(footer)組成。我們接下來就圍繞博客布局去介紹網格布局的基本概念。
網格布局術語
- 網格容器
- 網格線
- 網格軌道
- 網格單元格
- 網格區域
網格容器
網格容器為其中的內容建立新的 網格格式化上下文 ( grid formatting context ),網格容器構成了內部網格項的邊界
網格線
網格線是水平和垂直分隔線。 我們將使用它們來構建網格軌道,網格單元格和網格區域。 他們有一個數字索引,或者我們也可以給他們一個特定的名字。
網格軌道
網格軌道是兩條線之間的垂直或水平空間。
網格單元格
網格單元是在兩個相鄰的水平網格線和兩個相鄰的垂直網格線之間的項目。 它是我們可以把內容放入的最小單位。
網格區域
網格布局的完整實現
現在我們用網格布局實現一下博客布局:
<div class="blog"> <div class="header">Header</div> <div class="content">Content</div> <div class="sidebar">Sidebar</div> <div class="footer">Footer</div> </div>
首先我們要設置 display 為 grid 屬性,對于其他的設置,我使用絕對值(pixels)作為長度單位,當然,也有更好的其他嘗試(例如百分比、em、rem、vw和vh)。 屬性 grid-template-columns 和 grid-template-rows 將生成網格軌道劃分最外面的網格容器。 這兩個屬性的值既可以用固定值也可以使用auto。
.blog { display: grid; grid-template-columns: 400px 20px 180px; grid-template-rows: 100px 20px 210px 20px 100px; }
定義網格的外觀,看下面的代碼,以及代碼下面的解釋圖片:
.header { grid-row-start: 1; grid-row-end: 2; grid-column-start: 1; grid-column-end: 4; } .content { grid-row-start: 3; grid-row-end: 4; grid-column-start: 1; grid-column-end: 2; } .sidebar { grid-row-start: 3; grid-row-end: 4; grid-column-start: 3; grid-column-end: 4; } .footer { grid-row-start: 5; grid-row-end: 6; grid-column-start: 1; grid-column-end: 4; }
我們也可以使用縮寫:
.header { grid-row: 1 /2; grid-column: 1 /4; } .content { grid-row: 3 /4; grid-column: 1 /2; } .sidebar { grid-row: 3 /4; grid-column: 3 /4; } .footer { grid-row: 5 / 6; grid-column: 1 / 4; }
怎么樣才能更短呢? grid-area 遵循以下順序: grid-row-start , grid-column-start , grid-row-end , grid-column-end
.header { grid-area: 1 / 1 / 2 / 4; } .content { grid-area: 3 / 1 / 4 / 2; } .sidebar { grid-area: 3 / 3 / 4 / 4; } .footer { grid-area: 5 / 1 / 6 / 4; }
最終代碼是這樣的:
.wrapper { display: grid; grid-template-columns: 400px 20px 180px; grid-template-rows: 100px 20px 210px 20px 100px; } .header { grid-area: 1 / 1 / 2 / 4; } .content { grid-area: 3 / 1 / 4 / 2; } .sidebar { grid-area: 3 / 3 / 4 / 4; } .footer { grid-area: 5 / 1 / 6 / 4; }
上面這個例子很容易讓你對即將到來的CSS網格布局充滿憧憬,它真的是很好玩的東西,它入門很簡單,通俗易懂,使人非常容易接受。但是更深入的接觸之后會發現其實網格布局是很復雜的,甚至超過了Flexbox,它足足有17個新特性,并且圍繞著我們編寫CSS的方式介紹了許多新的概念,所以為了理解這個新的規范,弄清實戰中它是怎樣工作的,我們用它來創建一個圣杯布局。
什么是圣杯布局(Holy Grail Layout)
圣杯布局是一種網頁布局,由四部分組成:一個頁眉,頁腳和一個主要內容區域,有兩個側邊,每邊一個。布局遵循一下規則:
- 兩邊帶有固定寬度中間可以流動(fluid)
- 中心列最先出現在標記中
- 所有三列不管其中內容如何變化,都應該是相同的高度
- 頁腳應該總是在瀏覽器視窗的底部,即便內容不填滿整個適口的寬度
- 響應式布局,在較小的視口中,各部分要進行折疊,寬度100%顯示
圣杯布局在CSS中,如果不用任何Hack是很難去實現的。
用網格布局的解決方案
html
<body class="hg"> <header class="hg__header">Title</header> <main class="hg__main">Content</main> <aside class="hg__left">Menu</aside> <aside class="hg__right">Ads</aside> <footer class="hg__footer">Footer</footer> </body>
它的CSS只有31行!
.hg__header { grid-area: header; } .hg__footer { grid-area: footer; } .hg__main { grid-area: main; } .hg__left { grid-area: navigation; } .hg__right { grid-area: ads; } .hg { display: grid; grid-template-areas: "header header header" "navigation main ads" "footer footer footer"; grid-template-columns: 150px 1fr 150px; grid-template-rows: 100px 1fr 30px; min-height: 100vh; } @media screen and (max-width: 600px) { .hg { grid-template-areas: "header" "navigation" "main" "ads" "footer"; grid-template-columns: 100%; grid-template-rows: 100px 50px 1fr 50px 30px; } }
分解代碼
上面說過,CSS網格布局可以非常復雜,然后,我創建這個圣杯布局只用了17個新特性的4個:
- grid-area
- grid-template-areas
- grid-template-columns
- grid-template-rows
我們用這些網格屬性去實現圣杯布局布局可分為5個步驟。
1.定義網格
我們要做的第一件事情就是確認網格的區域,所以我們可以在創建網格時通過這個別名來引用它們。 我們使用 grid-area 屬性。
.hg__header { grid-area: header; } .hg__footer { grid-area: footer; } .hg__main { grid-area: main; } .hg__left { grid-area: navigation; } .hg__right { grid-area: ads; }
然后,使用 grid-template-areas 屬性,我們可以用非常直觀的方式指定網格的布局。 grid-template-areas 屬性接受一個空格分隔的字符串列表,每個字符串表示一行。 在每個字符串中,我們有一個空格分隔的網格區域列表,定義的每個網格區域占用一列。 因此,如果我們想要一個區域跨越兩列,我們定義它兩次。 在我們的圣杯布局中,我們有3列和3行。 頁眉和頁腳行橫跨3列,而其他區域各跨1列。
.hg { display: grid; grid-template-areas: "header header header" "navigation main ads" "footer footer footer"; }
使用這個標記,我們得到以下的結果:
2.定義列寬
下一步,我們要定義的列的寬度。我們使用 grid-template-columns 屬性定義列的寬度。該屬性接受空格分格的寬度列表,網格中的每一列都有一個寬度。因為我們的布局有3列,我們可以指定3個寬度:
grid-template-columns: [column 1 width] [column 2 width] [column 3 width];
對于圣杯布局,我們希望2個側邊寬度為150px。
.hg { grid-template-columns: 150px [column 2 width] 150px; }
我們還希望中間列占據空間的其余部分。 我們可以通過使用新的 fr 單位來做到這一點。 此單位表示網格中剩余的自由空間的一小部分。 在我們的例子中,剩余自由空間是網格的當前寬度減去300px(兩個邊欄的寬度)。
.hg { grid-template-columns: 150px 1fr 150px; }
設置網格列之后,這是布局的樣子 :
3.定義行高
接下來,我們要定義行的高度。 類似于我們 grid-template-columns 定義列寬,我們使用 grid-template-rows 定義行高。此屬性還接受用空格分隔列表。雖然我們可以寫在一行,但是我認為一行一行去寫會更加直觀清楚。
.hg { grid-template-rows: 100px 1fr 30px; }
因此,我們的標題高度是100px,我們的頁腳高度是30px,中間行(主要內容和兩個側邊欄)占用 .hg 元素的剩余可用空間。
4.固定頁腳
在圣杯布局中,我們希望頁腳始終位于視口的底部,即使頁面上的內容不被充滿一屏。 為了實現這一點,我們可以將 .hg 元素的最小高度設置為視口的高度。
.hg { min-height: 100vh; }
因為我們指定中間行應該填充剩余的可用空間,它會伸展到填滿屏幕。
5.設置響應式
最后,我們想讓布局響應。 在較小的設備上,所有網格項目應該一個接一個地顯示在一列中。 為此,我們需要重新定義之前定義的3個屬性: grid-template-areas , grid-template-columns 和 grid-template-rows 。 首先,我們想要網格中的所有項目按照特定的順序在一個列中:
@media screen and (max-width: 600px) { .hg { grid-template-areas: "header" "navigation" "main" "ads" "footer"; } }
接下來,我們想要所有項目占滿網格寬度的100%:
@media screen and (max-width: 600px) { .hg { grid-template-columns: 100%; } }
最后,我們需要重置每一行的高度。 除了主行之外,所有行限定它的高度:
@media screen and (max-width: 600px) { .hg { grid-template-rows: 100px /* Header */ 50px /* Navigation */ 1fr /* Main Content */ 50px /* Ads */ 30px; /* Footer */ } }
完成!在這里你可以看到它的 演示和源碼 (你可能需要在瀏覽器中啟用實驗性的網絡功能來查看它)
Grid Layout Module vs Flexbox
Flexbox適用于許多布局和很多“頁面組件”元素,因為它們大多是基本線性的。 Grid適用于整體頁面布局,以及非線性的復雜頁面組件。
這兩個可以任意組合,所以一旦廣泛支持,我相信大多數頁面將由一個外部網格的整體布局,混合嵌套flexbox和網格的頁面組件,最后 block / inline-block / table 布局在頁面裝飾文本和內容。
網格布局資源
上面講的兩種布局只使用了網格布局的4種屬性,沒有涵蓋所有的網格布局概念和語法,如果對網格布局有興趣,可以去下面的資源中更深入學習:
A Complete Guide to CSS Grid Layout
CSS Grid Layout Examples Grid by Example
The future of layout with CSS: Grid Layouts
還有 Rachel Andrew 的關于網格布局的 最新信息和資源 。 她為網格布局做了許多貢獻。
總結
正如你所看到的,即將到來的CSS網格布局是強大的,因為它的代碼簡潔易懂,你很容易去設計和改變布局順序。這些功能可以幫助我們永久改變網絡開發中創建布局的方式,所以,我相信網格布局是CSS布局的未來!
http://chris.house/blog/a-complete-guide-css-grid-layout/
https://en.wikipedia.org/wiki/Holy Grail (web_design)
https://bitsofco.de/holy-grail-layout-css-grid/
https://www.sitepoint.com/introduction-css-grid-layout-module/
來自:https://fe.ele.me/wang-ge-bu-ju-css-grid-layout-qian-tan/