簡介
CSS Grid布局 (又名"網格"),是一個基于二維網格布局的系統,主要目的是改變我們基于網格設計的使用者接口方式。如我們所知,CSS 總是用于網頁的樣式設定,但它并沒有起到很好的作用。剛開始的時候我們使用表格(table),然後使用浮動(float)、 定位(position)和内聯塊(inline-block),但所有這些方法本質上來講都是hacks,存留了很多需要實作的重要功能問題(例如,垂直居中)。雖然Flexbox可以起到一定的補救作用,但是它隻可以實作簡單的一維布局,并不适用于複雜的二維布局(實際上 Flexbox 和 Grid 可以一起結合使用起到最佳效果)。網格是 CSS 第一次專門建立的子產品,用來解決我們之前在制作網站時使用hacks處理布局問題。
這裡有兩件事情啟發我建立本指南。第一個是 Rachel Andrew 的令人敬畏的書--為 CSS Grid 布局做好準備。這本書很詳盡明确的的介紹了Grid,如果你想很好的掌握Grid的基礎知識,我強烈建議你去購買。另外一個很大的靈感來自于 Chris Coyier 的-- Flexbox完整指南,這本書是我了解Flebox的一個很優秀的資源。這裡,我還想補充一句,當你使用谷歌搜尋"flexbox"時,會出現很多類似的資源,但是為什麼不直接利用最好的資源呢?
我書寫此指南的目的是基于目前最新版本,規範其網格概念。是以我不會再次提及過時的 IE 文法,并且随着規範的成熟,我會盡力定期更新此指南。
基礎知識與浏覽器支援
Grid 的入門是很容易的。你隻需要定義一個容器元素并設定display:grid,使用grid-template-columns 和 grid-template-rows屬性設定網格的列與 行的大小,然後使用grid-column 和 grid-row屬性将其子元素放入網格之中。與flexbox類似,網格項的源順序無關緊要。為了更好地使你的網格與媒體查詢相結合使用,你可以在 CSS 中任意放置。想象一下你定義的整個頁面布局,然後如果想要完全重新布局以适應不同的螢幕寬度,這時僅僅使用幾行 CSS 代碼就可以實作。Grid是曾經介紹過的最強大 CSS 子產品之一。
關于 Grid 一件很重要的事情就是它現在還不适用于項目使用。目前還處于 W3C 的工作草案之中,并且預設情況下,還不被所有的浏覽器所支援。Internet Explorer 10 和 11 已經可以實作支援,但也是利用一種過時的文法實作的。現在出于示例示範,我建議你使用啟用了特殊标志的 Chrome, Opera 或者 Firefox 。在 Chrome,導航到chrome://flags 并啟用" web 實驗平台功能"。該方法同樣适用于 Opera (opera://flags)。在Firefox中,啟用 layout.css.grid.enabled 标志。
這裡有一張浏覽器支援情況的表格(之後我會繼續更新):
除了Microsoft,浏覽器廠商似乎想要等到Grid規範成熟後再加以推廣。這是一件好事,因為這意味着我們就不需要擔心學習多個文法。
等待 Grid 的使用,隻是時間的問題。但是現在你需要開始學習它了。
重要術語
在深入研究Grid之前,我們需要了解其相關術語概念。因為這裡涉及到的術語在概念上都有點類似,如果你沒有首先記住Grid規範中的相關定義,你就會很容易将其與另一個概念相混淆。但是不需要擔心,這裡的屬性并不是很多。
網格容器(Grid Container)
當一個元素設定display: grid屬性時,它就會成為所有網格項(Grid Items)的父元素。在下面的示例中,container就是網格容器。
<div class="container">
<div class="item item-1"></div>
<div class="item item-2"></div>
<div class="item item-3"></div>
</div>
網格項(Grid Item)
網格容器的孩子(e.g. 子元素)。這裡item元素都是網格項,但是sub-item不包含其中。
<div class="container">
<div class="item"></div>
<div class="item">
<p class="sub-item"></p>
</div>
<div class="item"></div>
</div>
網格線(Grid Line)
分界線構成了網格的結構。他們可以是垂直的("列網格線")也可以是水準的("行網格線"),并且存在于一行或一列的任一側。下面圖檔中的黃線就是列網格線的一個例子。
網格軌道(Grid Track)
兩個相鄰網格線之間的空間。你可以把它們想像成網格的行或列。下圖所示的是第二行和第三行網格線之間的網格軌道。
網格單元格(Grid Cell)
兩個相鄰的行和兩個相鄰的列之間的網格線空間。它是網格的一個"機關"。下面圖檔所示的是行網格線 1 和 2 與列網格線 2 和 3 之間的網格單元格。
網格區域(Grid Area)
四條網格線所包圍的所有空間。網格區域可由任意數量的網格單元格組成。下面圖檔所示的是行網格線 1 和 3 和列網格線 1 和 3 之間的網格區域。
網格容器屬性(Grid Container)
display
定義一個元素成為網格容器,并對其内容建立一個網格格式的上下文。
屬性值:
- grid: 産生一個塊級的網格
- inline-grid: 産生内聯級網格
.container{
display: grid | inline-grid
}
注: column, float, clear, 和 vertical-align 元素對網格容器不起作用。
grid-template-rows
利用以空格分隔的值定義網格的列和行。值的大小代表軌道的大小,并且它們之間的空格表示網格線。
屬性值:
- <track-size>: 可以是一個長度、百分比或者是網格中自由空間的一小部分(使用fr機關)
- <line-name>: 你選擇的任意名稱
- subgrid - 如果你的網格容器本身就是一個網格項(即嵌套網格),你可以使用此屬性指定行和列的大小繼承于父元素而不是自身指定。
.container{
grid-template-columns: <track-size> ... | <line-name> <track-size> ... | subgrid;
grid-template-rows: <track-size> ... | <line-name> <track-size> ... | subgrid;
}
示例:
當你在值之間留有空格時,網絡線就會自動配置設定數值名稱:
.container{
grid-template-columns: 40px 50px auto 50px 40px;
grid-template-rows: 25% 100px auto;
}
但是你也可以顯示命名,請參考下面括号文法中的名稱命名方式:
.container{
grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];
grid-template-rows: [row1-start] 25% [row1-end] 100% [third-line] auto [last-line];
}
請注意,一條網格線可以具有有多個名稱。例如,這裡的第二行将有兩個名字: row1-end 和 row2-start:
.container{
grid-template-rows: [row1-start] 25% [row1-end row2-start] 25% [row2-end];
}
如果你的定義中包含重複的部分,你可以使用 repeat() 表示法進行精簡:
.container{
grid-template-columns: repeat(3, 20px [col-start]) 5%;
}
等效于:
.container{
grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start] 5%;
}
fr 機關允許你将一個軌道大小設定為網格容器内自由空間的一小部分。如下所示,每個網格項就會占據網格容器寬度的三分之一:
.container{
grid-template-columns: 1fr 1fr 1fr;
}
這裡自由空間表示除去非彈性項以後剩餘的空間。在此示例中的 fr 機關的可用空間表示減去50px以後的空間大小:
.container{
grid-template-columns: 1fr 50px 1fr 1fr;
}
grid-template-areas
使用grid-area屬性定義網格區域名稱,進而定義網格模闆。網格區域重複的名稱就會導緻内容跨越這些單元格。句點表示一個空單元格。文法本身提供了一種可視化的網格結構。
屬性值:
- <grid-area-name>: 使用grid-area屬性定義網格區域名稱
- .: 句點表示一個空單元格
- none: 無網格區域被定義
.container{
grid-template-areas: "<grid-area-name> | . | none | ..."
"..."
}
示例:
.item-a{
grid-area: header;
}
.item-b{
grid-area: main;
}
.item-c{
grid-area: sidebar;
}
.item-d{
grid-area: footer;
}
.container{
grid-template-columns: 50px 50px 50px 50px;
grid-template-rows: auto;
grid-template-areas: "header header header header"
"main main . sidebar"
"footer footer footer footer"
}
這将建立一個四列三行的網格。最上面的一行為header區域。中間一行由兩個main區域,一個空單元格和一個sidebar區域。最後一行是footer區域。
你所聲明的每一行都需要具有相同數目的單元格。
你可以使用任意數量的句點(.)聲明單個空單元格。隻要句點之間沒有空格就表示一個空單元格。
注意,你隻是使用此文法進行網格區域命名,而不是網格線命名。當你使用此文法時,區域兩邊的線就會得到自動命名。如果網格區域名稱為foo,則其行線和列線的名稱就将為foo-start,最後一行線及其最後一列線的名字就會為foo-end。這意味着一些線就可能具有多個名稱,如上面示例中所示,擁有三個名稱: header-start, main-start, 以及footer-start。
grid-column-gap和grid-row-gap
指定網格線的大小。你可以把它想像成在行/列之間設定間距寬度。
屬性值:
- <line-size>: 一個長度值
.container{
grid-column-gap: <line-size>;
grid-row-gap: <line-size>;
}
示例:
.container{
grid-template-columns: 100px 50px 100px;
grid-template-rows: 80px auto 80px;
grid-column-gap: 10px;
grid-row-gap: 15px;
}
間距僅僅在列/行之間産生,而不會在邊緣區。
grid-gap
grid-column-gap 和 grid-row-gap的簡寫值。
屬性值:
- <grid-column-gap> <grid-row-gap>: 長度值
.container{
grid-gap: <grid-column-gap> <grid-row-gap>;
}
示例:
.container{
grid-template-columns: 100px 50px 100px;
grid-template-rows: 80px auto 80px;
grid-gap: 10px 15px;
}
如果沒有指定grid-row-gap屬性的值,預設與grid-column-gap屬性值相同
justify-items
沿列軸對齊網格項中的内容(相反于align-item屬性定義的沿行軸對齊)。此值适用于容器内所有的網格項。
屬性值:
- start: 内容與網格區域的左端對齊
- end: 内容與網格區域的右端對齊
- center: 内容處于網格區域的中間位置
- stretch: 内容寬度占據整個網格區域空間(預設值)
.container{
justify-items: start | end | center | stretch;
}
示例:
.container{
justify-items: start;
}
.container{
justify-items: end;
}
.container{
justify-items: center;
}
.container{
justify-items: stretch;
}
這也可以使用justify-self屬性對各個網格項進行設定。
align-items
沿行軸對齊網格項中的内容(相反于justify-item屬性定義的沿列軸對齊)。此值适用于容器内所有的網格項。
屬性值:
- start: 内容與網格區域的頂端對齊
- end: 内容與網格區域的底部對齊
- center: 内容處于網格區域的中間位置
- stretch: 内容高度占據整個網格區域空間(預設值)
.container{
align-items: start | end | center | stretch;
}
示例:
.container{
align-items: start;
}
.container{
align-items: end;
}
.container{
align-items: center;
}
.container{
align-items: stretch;
}
這也可以使用align-self屬性對各個網格項進行設定。
justify-content
當你使用px這種非響應式的機關對你的網格項進行大小設定時,就有可能出現一種情況--你的網格大小可能小于其網格容器的大小。在這種情況下,你就可以設定網格容器内網格的對齊方式。此屬性會将網格沿列軸進行對齊(相反于align-content屬性定義的沿行軸對齊)。
屬性值:
- start: 網格與網格容器的左端對齊
- end: 網格與網格容器的右端對齊
- center: 網格處于網格容器的中間
- stretch: 調整網格項的大小,使其寬度填充整個網格容器
- space-around: 在網格項之間設定偶數個空格間隙,其最邊緣間隙大小為中間空格間隙大小的一半
- space-between: 在網格項之間設定偶數個空格間隙,其最邊緣不存在空格間隙
- space-evenly: 在網格項之間設定偶數個空格間隙,同樣适用于最邊緣區域
.container{
justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
}
示例:
.container{
justify-content: start;
}
.container{
justify-content: end;
}
.container{
justify-content: center;
}
.container{
justify-content: stretch;
}
.container{
justify-content: space-around;
}
.container{
justify-content: space-between;
}
.container{
justify-content: space-evenly;
}
align-content
當你使用px這種非響應式的機關對你的網格項進行大小設定時,就有可能出現一種情況--你的網格大小可能小于其網格容器的大小。在這種情況下,你就可以設定網格容器内網格的對齊方式。此屬性會将網格沿行軸進行對齊(相反于justify-content屬性定義的沿列軸對齊)。
屬性值:
- start: 網格與網格容器的頂端對齊
- end: 網格與網格容器的底部對齊
- center: 網格處于網格容器的中間
- stretch: 調整網格項的大小,使其高度填充整個網格容器
- space-around: 在網格項之間設定偶數個空格間隙,其最邊緣間隙大小為中間空格空隙大小的一半
- space-between: 在網格項之間設定偶數個空格間隙,其最邊緣不存在空格間隙
- space-evenly: 在網格項之間設定偶數個空格間隙,同樣适用于最邊緣區域
.container{
align-content: start | end | center | stretch | space-around | space-between | space-evenly;
}
示例:
.container{
align-content: start;
}
.container{
align-content: end;
}
.container{
align-content: center;
}
.container{
align-content: stretch;
}
.container{
align-content: space-around;
}
.container{
align-content: space-between;
}
.container{
align-content: space-evenly;
}
grid-auto-columns和grid-auto-rows
指定任何自動生成的網格軌道(隐式網格跟蹤)的大小。當你顯式定位行或列(使用 grid-template-rows/grid-template-columns屬性)時,就會産生超出定義範圍内的隐式網格軌道。
屬性值:
- <track-siz>: 可以是長度、 百分比或網格自由空間的一小部分(使用fr機關)
.container{
grid-auto-columns: <track-size> ...;
grid-auto-rows: <track-size> ...;
}
為了說明隐式網格軌道是如何被創造出來的,請思考如下代碼:
.container{
grid-template-columns: 60px 60px;
grid-template-rows: 90px 90px
}
這裡建立了一個2 x 2 的網格。
但是現在你想象你使用grid-column 和 grid-row 來定位網格項,如下所示:
.item-a{
grid-column: 1 / 2;
grid-row: 2 / 3;
}
.item-b{
grid-column: 5 / 6;
grid-row: 2 / 3;
}
這裡我們定義.item b開始于列線 5 并結束于在列線 6,但是我們從來沒有定義列線 5 或 6。因為我們引用不存在的線,寬度為0的隐式軌道的就會被建立用來填補空白。我們可以使用grid-auto-columns 和 grid-auto-rows屬性來設定這些隐式軌道的寬度:
.container{
grid-auto-columns: 60px;
}
grid-auto-flow
如果你不顯式的在網格中放置網格項,自動布局算法就會自動踢出此網格項。此屬性用來控制自動布局算法的工作原理。
屬性值:
- row: 告訴自動布局算法填充每一行,必要時添加新行
- column: 告訴自動布局算法填充每一列,必要時添加新列
- dense: 告訴自動布局算法試圖填補網格中之前較小的網格項留有的空白
.container{
grid-auto-flow: row | column | row dense | column dense
}
注意:dense值可能會導緻更改網格項的順序。
示例:
考慮如下HTMl代碼:
<section class="container">
<div class="item-a">item-a</div>
<div class="item-b">item-b</div>
<div class="item-c">item-c</div>
<div class="item-d">item-d</div>
<div class="item-e">item-e</div>
</section>
這裡定義了一個兩列五行的網格,并将 grid-auto-flow屬性設定為row(即預設值):
.container{
display: grid;
grid-template-columns: 60px 60px 60px 60px 60px;
grid-template-rows: 30px 30px;
grid-auto-flow: row;
}
将網格項放置在網格中時隻需要其中的兩個網格項:
.item-a{
grid-column: 1;
grid-row: 1 / 3;
}
.item-e{
grid-column: 5;
grid-row: 1 / 3;
}
因為我們将grid-auto-flow屬性設定為了row,是以我們的網格看起來會像這個樣子。注意我們我們沒有對其進行設定的三個網格項(item-b, item-c and item-d),會沿行軸進行布局。
如果我們将grid-auto-flow屬性設定為 column,item-b, item-c 和 item-d 就會沿列軸進行布局。
.container{
display: grid;
grid-template-columns: 60px 60px 60px 60px 60px;
grid-template-rows: 30px 30px;
grid-auto-flow: column;
}
grid
在一行聲明中設定一下所有屬性的簡寫形式:grid-template-rows, grid-template-columns, grid-template-areas, grid-auto-rows, grid-auto-columns, 以及 grid-auto-flow。它将 grid-column-gap 和 grid-row-gap屬性設定為初始值,即使它們不能顯示的設定此屬性。
屬性值:
- none: 将所有的子屬性設定為初始值
- subgrid: 将grid-template-rows 和 grid-template-columns屬性值設定為subgrid,其餘子屬性設定為初始值
- <grid-template-rows> / <grid-template-columns>: 将grid-template-rows 和 grid-template-columns屬性值設定為指定值,其餘子屬性設定為初始值
- <grid-auto-flow>[<grid-auto-rows> [ / <grid-auto-columns>] ] : grid-auto-flow, grid-auto-rows 和 grid-auto-columns屬性分别接受相同的值,如果省略了grid-auto-columns屬性,它将設定為grid-auto-rows屬性的值。如果兩者均被忽略,那麼都将被設定為初始值。
.container{
grid: none | subgrid | <grid-template-rows> / <grid-template-columns> | <grid-auto-flow> [<grid-auto-rows> [/ <grid-auto-columns>]];
}
示例:
下面兩個代碼塊是等效的:
.container{
grid: 200px auto / 1fr auto 1fr;
}
.container{
grid-template-rows: 200px auto;
grid-template-columns: 1fr auto 1fr;
grid-template-areas: none;
}
同樣,下面的兩個代碼塊也是等效的:
.container{
grid: column 1fr / auto;
}
.container{
grid-auto-flow: column;
grid-auto-rows: 1fr;
grid-auto-columns: auto;
}
它還接受一次性設定所有屬性,更複雜但非常友善的文法。指定grid-template-areas, grid-auto-rows 和 grid-auto-columns屬性,其他所有子屬性都将設定為其初始值。你現在所做的是在其網格區域内,指定網格線名稱和内聯軌道大小。下面是最簡單的描述:
.container{
grid: [row1-start] "header header header" 1fr [row1-end]
[row2-start] "footer footer footer" 25px [row2-end]
/ auto 50px auto;
}
等效于:
.container{
grid-template-areas: "header header header"
"footer footer footer";
grid-template-rows: [row1-start] 1fr [row1-end row2-start] 25px [row2-end];
grid-template-columns: auto 50px auto;
}
網格項屬性(Grid Items)
grid-column-start/grid-column-end/grid-row-start/grid-row-end
使用特定的網格線确定網格項在網格内的位置。grid-column-start/grid-row-start 屬性表示網格項的網格線的起始位置,grid-column-end/grid-row-end屬性表示網格項的網格線的終止位置。
屬性值:
- <line>: 可以是一個數字來引用相應編号的網格線,或者使用名稱引用相應命名的網格線
- span <number>: 網格項包含指定數量的網格軌道
- span <name>: 網格項包含指定名稱網格項的網格線之前的網格軌道
- auto: 表明自動定位,自動跨度或者預設跨度之一
.item{
grid-column-start: <number> | <name> | span <number> | span <name> | auto
grid-column-end: <number> | <name> | span <number> | span <name> | auto
grid-row-start: <number> | <name> | span <number> | span <name> | auto
grid-row-end: <number> | <name> | span <number> | span <name> | auto
}
示例:
.item-a{
grid-column-start: 2;
grid-column-end: five;
grid-row-start: row1-start
grid-row-end: 3
}
.item-b{
grid-column-start: 1;
grid-column-end: span col4-start;
grid-row-start: 2
grid-row-end: span 2
}
如果沒有聲明grid-column-end/grid-row-end屬性,預設情況下網格項的跨度為1。
網格項可以互相重疊。可以使用z-index屬性控制堆疊順序。
grid-column/grid-row
grid-column-start + grid-column-end, 和 grid-row-start + grid-row-end屬性分别的簡寫形式。
屬性值:
- <start-line> / <end-line>: 每一個屬性均接收一個相同值,包括跨度。
.item{
grid-column: <start-line> / <end-line> | <start-line> / span <value>;
grid-row: <start-line> / <end-line> | <start-line> / span <value>;
}
示例:
.item-c{
grid-column: 3 / span 2;
grid-row: third-line / 4;
}
如果沒有聲明結束網格線值,預設網格軌道跨度為1.
grid-area
給網格項進行命名以便于模闆使用grid-template-areas屬性建立時可以加以引用。另外也可以被grid-row-start + grid-column-start + grid-row-end + grid-column-end屬性更為簡潔的加以引用。
屬性值:
- <name>: 你所定義的名稱
- <row-start> / <column-start> / <row-end> / <column-end>: 可以為數字或者名稱
.item{
grid-area: <name> | <row-start> / <column-start> / <row-end> / <column-end>;
}
示例:
對網格項進行命名的一種方式:
.item-d{
grid-area: header
}
grid-row-start + grid-column-start + grid-row-end + grid-column-end屬性的一種簡寫方式:
.item-d{
grid-area: 1 / col4-start / last-line / 6
}
justify-self
沿列軸對齊網格項中的内容(相反于align-item屬性定義的沿行軸對齊)。此值适用于單一網格項中的内容。
屬性值:
- start: 内容與網格區域的左端對齊
- end: 内容與網格區域的右端對齊
- center: 内容處于網格區域的中間位置
- stretch: 内容寬度占據整個網格區域空間(預設值)
.item{
justify-self: start | end | center | stretch;
}
示例
.item-a{
justify-self: start;
}
.item-a{
justify-self: end;
}
.item-a{
justify-self: center;
}
.item-a{
justify-self: stretch;
}
設定網格中所有網格項的對齊方式,可以使用網格容器上的justify-items屬性。
align-self
沿行軸對齊網格項中的内容(相反于justify-item屬性定義的沿列軸對齊)。此值适用于單一網格項中的内容。
屬性值:
- start: 内容與網格區域的頂端對齊
- end: 内容與網格區域的底部對齊
- center: 内容處于網格區域的中間位置
- stretch: 内容高度占據整個網格區域空間(預設值)
.item{
align-self: start | end | center | stretch;
}
示例:
.item-a{
align-self: start;
}
.item-a{
align-self: end;
}
.item-a{
align-self: center;
}
.item-a{
align-self: stretch;
}
使網格中所有的網格項對齊,可以使用網格容器上的align-items屬性。