CSS 中的 Grid 佈局 完全指南
Grid 是一個基於二維網格佈局的系統,有了它我們可以非常方便的實現過去很複雜佈局,無需再使用 float
, inline-block
, position
這些本質上是 hack 的方法。
CSS網格佈局擅長於將一個頁面劃分為幾個主要區域,以及定義這些區域的大小、位置、層次等關係(前提是HTML生成了這些區域)。
它像表格一樣,網格佈局讓我們能夠按行或列來對齊元素。 然而在佈局上,網格比表格更可能做到或更簡單。
網格佈局概念
在學習之前需要了解以下網格的幾個概念。
網格軌道(Grid Tracks)
網格軌道 是兩條網格線之間的空間。它們通過使用屬性 grid-template-columns
和 grid-template-rows
在網格中定義。

上圖中有兩行三列,一行或一列就叫做軌道。
網格線(Grid Lines)
使用 Grid
佈局在顯式網格中定義軌道的同時會建立網格線。
網格線可以用它們的編號來定址。在從左到右的語言中, 列線1
將位於網格的左側, 行線1
將位於其頂部。線編號遵循文件的寫入模式,因此在從右到左的語言中, 列線1
行將位於網格的右側。下面的圖片展示了該網格的線編號,假設語言是從左到右的。

網路單元格(Grid Cell)
在 Grid
佈局中,網路單元格是 CSS 網格中的最小單元。它是四條網格線之間的空間,非常像表格單元格。

網格區域(Grid Areas)
網格區域是網格中由一個或者多個網格單元格組成的一個矩形區域。本質上,網格區域一定是矩形的。例如,不可能建立T形或L形的網格區域。

網格間距(Gutters)
網格間距是網格軌道之間的間距,可以通過 grid-column-gap
, grid-row-gap
在Grid佈局中建立。

使用 Grid 佈局
和 flex 類似,要使用網格佈局,首先要有一個容器,將一個元素的 display
設定為 grid
就可以得到一個 grid 容器。容器的子項就是網格項(grid items),它有點類似 table
中的 td
,但是更加靈活。
float
, clear
, 和 vertical-align
元素對網格容器不起作用。
容器上的屬性
網格模板
建立了網格容器,我們就可以定義這個網格有多少行有多少列,並且每一行每一列的大小。
grid-template-rows
我們使用 grid-template-rows
來顯性定義網格有多少行。它可以取如下的值:
-
none
關鍵字,表示不明確的網格。所有的行和其大小都將由grid-auto-rows
屬性隱式的指定。 -
非負值的長度大小
:如px, em, vw
等 -
百分比
:相對於網格容器的,如果是inline-grid
,則百分比值將被視為auto
-
flex
:非負值,用單位fr
來定義網格軌道大小的彈性係數。每個定義了flex
的網格軌道會按比例分配剩餘的可用空間 -
max-content
關鍵字,表示以網格項的最大的內容來佔據網格軌道的 -
min-content
關鍵字,表示以網格項的最大的最小內容來佔據網格軌道 -
auto
如果該網格軌道為最大時,等同於max-content
,為最小時,等同於min-content
grid-template-columns
它和 grid-template-rows
類似,一個設定網格行,一個是設定網格列。
.container { display: grid; grid-template-columns: 40px 50px auto 50px 40px; grid-template-rows: 25% 100px auto; } 複製程式碼

.container { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 100px 100px; } 複製程式碼

Grid 中可以使用的函式
在 Grid 佈局中我們還可以使用如下 3 個函式
repeat()
repeat
函式可以以一種更簡潔的方式去表示大量而且重複行的表示式。
比如上面 grid-template-columns: 1fr 1fr 1fr;
我們可以寫成 repeat(3, 1fr)
。它的第一個引數是重複的次數,而可以為 auto-fill
和 auto-fit
。
auto-fill
如果容器有明確的大小或最大大小,則重複次數是最大可能的正整數,不會導致網格溢位其網格容器。如果任何重複次數都會溢位,則重複次數為1。

auto-fit
與 auto-fill
的行為相同,只是在放置網格項後,任何空的重複軌道都會摺疊。

#container { display: grid; grid-template-columns: repeat(2, 50px 1fr) 100px; grid-gap: 5px; box-sizing: border-box; height: 200px; width: 100%; background-color: #8cffa0; padding: 10px; } #container > div { background-color: #8ca0ff; padding: 5px; } 複製程式碼

minmax()
定義了一個長寬範圍的閉區間。它接受兩個引數,最小值 和 最大值。它返回這個區間中的值。
如 minmax(max-content, 300px)
,最大不能大於 300px
minmax(200px, 1fr)
最小不能小於 200px
fit-content()
它相當於 min(maximum size, max(minimum size, argument))
。引數可以是長度值和百分比。
它在內容的最小值和引數中去一個最大值,然後再在內容的最大值中取一個最小值。
也就是當內容少時,它取內容的長度,如果內容多,內容長度大於引數長度時,它取引數長度。
grid-template-areas
這個屬性網格區塊,需要和 grid-area
配合使用,它的值可以是 none
和 字串
。
為字串時每一個給定的字串會生成一行,一個字串中用空格分隔的每一個單元(cell)會生成一列。多個同名的,跨越相鄰行或列的單元稱為網格區塊(grid area)。非矩形的網格區塊是無效的。
#page { display: grid; width: 100%; height: 250px; grid-template-areas: "head head" "navmain" "navfoot"; grid-template-rows: 50px 1fr 30px; grid-template-columns: 150px 1fr; } #page > header { grid-area: head; background-color: #8ca0ff; } #page > nav { grid-area: nav; background-color: #ffa08c; } #page > main { grid-area: main; background-color: #ffff64; } #page > footer { grid-area: foot; background-color: #8cffa0; } 複製程式碼

grid-template-areas
字串,關聯 grid item 的 grid-area
,用它定義一片區域。
grid-template
是 grid-template-rows
、 grid-template-columns
和 grid-template-areas
的簡寫。
它的值可以分三種情況:
-
none
- 只有定義行和列時可以使用
rows/columns
語法,如grid-template: 100px 1fr / 50px 1fr;
- 當三個都有時,也用一個
/
分隔,而且它的右邊也還是columns
,但是它的左邊語法是<line-names>? <string> <track-size>? <line-names>?
。
.page { grid-template: [header-top] "a a a"[header-bottom] [main-top]"b b b" 1fr [main-bottom] / auto 1fr auto; } /* line-names 是可選的,自定義名稱,需要使用中括號包裹,它其實相當於註釋 string 網格項 grid-area 的關聯值 track-size 這一行的大小 */ 複製程式碼
#page { display: grid; width: 100%; height: 200px; grid-template: [header-left] "head head" 30px [header-right] [main-left]"navmain" 1fr[main-right] [footer-left] "navfoot" 30px [footer-right] / 120px 1fr; } header { background-color: lime; grid-area: head; } nav { background-color: lightblue; grid-area: nav; } main { background-color: yellow; grid-area: main; } footer { background-color: red; grid-column: foot; } 複製程式碼

grid-row-gap / row-gap
用來設定行元素之間的間隙(gutter) 大小。它的值可以是長度值、百分比和 normal
。
CSS Grid Layout 起初是用 grid-row-gap 屬性來定義的,目前逐漸被 row-gap 替代。但是,為了相容那些不支援 row-gap 屬性的瀏覽器,你需要使用帶有字首的屬性。
.box{ grid-row-gap: 1em; } 複製程式碼

grid-column-gap / column-gap
用來設定元素列之間的間隔 (gutter) 大小。它的值可以是長度值、百分比和 normal
。
normal
在 多列布局 時預設間隔為1em,其他型別佈局預設間隔為 0。
和 grid-row-gap
一樣,它漸漸被 column-gap
取代。
.page { grid-column-gap: 1em; } 複製程式碼

grid-gap / gap
是上面兩個屬性的簡寫,語法是 row-gap column-gap
。如果沒有 column-gap
那麼它將被設定成跟 row-gap
一樣的的值。
它也漸漸被 gap
取代。
#grid { display: grid; height: 200px; grid-template: repeat(3, 1fr) / repeat(3, 1fr); gap: 20px 5px; } #grid > div { background-color: lime; } 複製程式碼

隱式建立的行和列
css gird 會根據周圍專案的大小和跨度自動調整網格上每個專案的位置。
比如:
.box { display: grid; grid-template: 25px / 100px 160px; background: #000; } .box * { background: #ccc; } .box *:nth-child(even) { background: #777; } 複製程式碼

我們只定義了一行,兩列。但是我們卻有 5 個子元素。CSS網格決定將它們擴充套件到隱式建立的空間,新建的隱式行中的列自動從先前指定的 grid-template-rows
屬性繼承行高。
grid-column-start
, grid-column-end
, grid-row-start
和 grid-row-end
這 4 個屬性是 grid item 上的,它可以定義一個 grid item 的位置,如果我們將它的位置設定的超出我們定義的網格,那時也會隱式建立行或列。
grid-auto-rows
指定了隱式建立行的大小。它的值可以是:
-
長度值
:px em vmax
等 -
百分比
:相對於網格容器 -
flex
:非負值,用單位fr
來定義網格軌道大小的彈性係數。每個定義了flex
的網格軌道會按比例分配剩餘的可用空間 -
max-content
關鍵字,表示以網格項的最大的內容來佔據網格軌道的 -
min-content
關鍵字,表示以網格項的最大的最小內容來佔據網格軌道 -
auto
如果該網格軌道為最大時,等同於max-content
,為最小時,等同於min-content
它的值和 grid-template-rows
是一樣的。
.box { display: grid; grid-template: 25px / 100px 160px; gap: 10px 20px; grid-auto-rows: 50px; background: #000; } .box * { background: #ccc; } .box *:nth-child(even) { background: #777; } 複製程式碼

grid-auto-columns
指定了隱式建立的網格的列寬。它的取值和 grid-auto-rows
一樣。
#grid { height: 100px; display: grid; grid-template-areas: "a a"; grid-gap: 10px; grid-auto-columns: 200px; } #grid > div { background-color: lime; } 複製程式碼

grid-auto-flow
控制著自動佈局演算法怎樣運作,精確指定在網格中被自動佈局的元素怎樣排列。
如果我們在一個 div
中寫幾個 div
,再對父級設定 display: grid;
,從視覺的角度可以發現沒什麼變化。但是如果我們再將父級 div
加上一句 grid-auto-flow: column;
我們就發現現在子元素在一行顯示,和彈性盒子效果差不多。
grid-auto-flow
的值如下:
row column
在這兩個關鍵字後面還可以加上 dense
關鍵字。語法是 [ row | column ] || dense
。
該關鍵字指定自動佈局演算法使用一種“稠密”堆積演算法,如果後面出現了稍小的元素,則會試圖去填充網格中前面留下的空白。這樣做會填上稍大元素留下的空白,但同時也可能導致原來出現的次序被打亂。
如果省略它,使用一種「稀疏」演算法,在網格中佈局元素時,佈局演算法只會「向前」移動,永遠不會倒回去填補空白。這保證了所有自動佈局元素「按照次序」出現,即使可能會留下被後面元素填充的空白。
grid-auto-flow: row;

grid-auto-flow: row dense;


grid
grid
是 CSS 簡寫屬性,它幾乎包括上面提到的所有屬性(除了 gap
)。
與其他簡寫屬性同樣,若有次級屬性未被宣告,其將使用初始值。另外,儘管此簡寫宣告無法設定網格的槽(gutter),槽會被該宣告重置。
它的值可以分為 3 類
grid-template
就和 grid-template
簡寫一樣,如 grid: [linename1] "a" 100px [linename2];
grid-template-rows / [ auto-flow && dense? ] grid-auto-columns?
grid-template-rows
設定行高( grid-template-columns
被設定為 none
), /
後面的 auto-flow
必須要寫( grid-auto-flow
被設定為 column
),最後 grid-auto-columns
置明確該如何自動重複列軌道( grid-auto-rows
屬性設為 auto
)。
如 grid: repeat(3, [line1 line2 line3] 200px) / auto-flow 300px;
[ auto-flow && dense? ] grid-auto-rows? / grid-template-columns
這種寫法和上種寫法相反,這種是設定 grid-template-columns
( rows
屬性為 none
)。可選的設定 grid-auto-rows
屬性( columns
為 auto
)
如 grid: auto-flow dense / 30%;
網格項上的屬性
grid-row-start, grid-row-end, grid-column-start, grid-column-end
分別指定 grid item 在網格中的行起始位,行結束位,列起始位,列結束位。
這就需要了解之前介紹的網格線概念,橫線(row)從上到下遞增,豎線(column)從做到右遞增,都是從 1 開始算。
它們可以取如下值:
-
auto
表示自動放置,自動跨度或預設span
為 1 -
數字
表示網格線 -
span 數字
表示跨越幾個格子,數字
小於等於0
無效。如果超過網格大小會隱式建立行或列。

它和 table
有點相似

如果設定的位置超出指定大小,會得到不穩定的效果,應該避免這種情況。

.box { display: grid; grid: 100px 100px / 100px 100px; background: #000; } .box * { background: #ccc; } .box *:nth-child(even) { background: #777; } .box1 { grid-column-start: span 5; } 複製程式碼

grid-row, grid-column
grid-row
和 grid-column
分別是上面 4 個屬性簡寫。
它們值的語法是 start / end
。如果只有一個值那麼它是 start
, end
值為預設 auto
。

當列數未知時,可以使用 -1
讓它一直擴充套件到網格末尾。

使用負值

grid-area
上面我們已經展示了 grid-area
和 grid-template-areas
結合的用法。 grid-area
其實是 grid-row-start
、 grid-column-start
、 grid-row-end
和 grid-column-end
的簡寫。
它的預設值是 grid-area: auto;
如果設定了 4 個值的話那麼它的順序是
grid-area: row-start / column-start / row-end / column-end;
如果設定了 3 個值,那麼最後一個為 auto
如果設定了 2 個值,那麼後兩個為 auto
如果設定了 1 個值,那麼後三個為 auto
如果第一項是 自定義表示
,那麼被忽略的都為自定義表示
.box1 { grid-area: a / a; } /* 相當於 */ .box1 { grid-row-start: a; grid-column-start: a; grid-row-end: a; grid-column-end: a; } 複製程式碼
網格項的內容對齊
我們可以使用 align-self
和 justify-self
調整 grid item 的內容對齊方式。
align-self
用來垂直方向對齊, justify-self
用來水平方向對齊。
align-self
flex 佈局也可以使用這個屬性。它常用如下 3 個值:
start center end

justify-self
它常用如下 3 個值:
-
start
/left
: 內容左對齊 -
cneter
: 內容水平居中 -
end
/right
: 內容右對齊
