熟練了Flex佈局之後,該學學Grid佈局了

語言: CN / TW / HK

theme: devui-blue

Grid的內容有點多,這一篇整理了概念和屬性,算是“理論”篇,後面會再寫一篇Grid的例子,當作“實踐”篇。如果覺得學了不知道用在哪裡的,可以關注下。

介紹

CSS Gird佈局也叫二維網格佈局系統,可用於佈局頁面主要的區域佈局或小型元件。網格是一組相交的水平線和垂直線,它定義了網格的列和行。我們可以指定將網格元素放置在與這些行和列相關的位置上。

一維佈局 和 二維佈局

像流佈局和Flex佈局,他們都是一維佈局。一維佈局一次只能處理一個維度上的元素佈局,一行或者一列。回想一下,流佈局和Flex佈局的兄弟節點,是不是都是按照行或者列來顯示的。

網格佈局是二維佈局,可以同時處理行和列上的佈局。使用網格佈局,兄弟節點可以被指定佈局到網格的某個位置。

所以,網格佈局相對流佈局Flex佈局更加的靈活,當然學習和使用也更加複雜。這篇文章會把網格佈局中的概念和屬性整理出來。如果覺得有用,還請點贊收藏。

下圖就是展示了一維佈局和二維佈局的不同。可以看出,如果佈局複雜,一維佈局需要增加節點來解決;而二維佈局,則不需要,這也是網格佈局強大而複雜的原因。

1.png

Grid佈局中的概念

網格容器

我們通過在元素上宣告 display:griddisplay:inline-grid 來建立一個網格容器。一旦我們這樣做,這個元素的所有直系子元素將成為網格元素。網格容器的設定和flex容器的設定類似。

在網格容器節點行,我們可以通過grid-template-columnsgrid-template-rows指定當前容器的行和列。

如下面的程式碼,就會生成一個2行3列的效果。 ```html

1
2
3
4
5

```

css .grid-box-1 { border: 1px solid #999; width: 300px; height: 200px; display: grid; margin: 20px; grid-template-columns: 1fr 1fr 1fr; /* 指定 3 列*/ grid-template-rows: 1fr 1fr; /* 指定 2行 */ } .grid-box-1 > div { background-color: bisque; border-radius: 4px; border: 1px solid #ccc; }

網格軌道

通過grid-template-columnsgrid-template-rows指定當前容器的行和列後,這裡的行和列就是網格軌道。但在實際頁面中,由於頁面的內容不確定,內容可能會超過grid-template-columnsgrid-template-rows指定的網格軌道個數,這個時候網格將會在隱式網格中建立行和列。按照預設,這些軌道將自動定義尺寸,所以會根據它裡面的內容改變尺寸。

你也可以在隱式網格中用 grid-auto-rowsgrid-auto-columns 屬性來定義一個設定大小尺寸的軌道。 還是拿上面的例子,如果Grid的子節點大於6個,就會出現隱式網格。

```html

1
2
3
4
5
6
7
8
9
10
11

```

css /* 隱式網格 */ .grid-box-2 { border: 1px solid #999; width: 300px; height: 200px; display: grid; margin: 20px; grid-template-columns: 1fr 1fr 1fr; grid-template-rows: 1fr 1fr; } .grid-box-2 > div { background-color: bisque; border-radius: 4px; border: 1px solid #ccc; }

上面的程式碼中,如果Grid的子節點超過了6個,父節點的高度是200,那麼超出指定網格軌道的子節點就是隱式網格,隱式網格不會根據網格軌道的樣式來進行設定。比如例子中就是,隱式網格的高度是內容的高度,父節點剩餘的空間會分配給兩個指定的網格軌道,軌道1:1比例分配。 當然,我們也可以設定隱式網格的樣式,通過grid-auto-rowsgrid-auto-columns可以對隱式網格的行列進行設定。如下面的例子,設定了隱式網格軌道的行高為40,那麼顯示網格高度就是60((200-40*2) / 2)。

css .grid-box-2 { grid-auto-rows: 40px; /* 新增隱式網格的行高30px */ }

網格線

設定網格軌道時,Grid會為我們建立帶編號的網格線來讓我們來定位每一個網格元素。還是拿上面的程式碼做例子,他的網格線編號會是下圖中的順序(負數表示從後往前的編號,不含隱式網格對應的網格線)。注意:網格線的編號順序取決於文章的書寫模式。

有了網格線,我們可以通過網格線指定跨軌道的網格元素,從而實現網格元素佔多行多列的效果。子元素通過grid-column-startgrid-column-endgrid-row-startgrid-row-end或者grid-columngrid-row,或者通過grid-area這一個屬性來設定來指定元素佔據的網格軌道。

這裡的屬性值不僅可以指定網格線,還可以指定span xx 這個的意思是佔據多少網格軌道。這個更符合我們的思維習慣。

這裡有7個屬性,其實很好記憶,佔據空間是通過指定網格線來指定的,所以會有行列 + 開始結束,這裡是4個屬性。然後行列的開始結束分別提供一個縮寫,這裡就是2個屬性。最後,可以通過grid-area一個屬性指定行列。 grid-area的順序是row-start / column-start / row-end / column-end。可以通過從左往右,從上往下,先startend來記憶。

```css .grid-box-3 > div:nth-of-type(1) { grid-column-start: 1; grid-column-end: 4; grid-row-start: 1; grid-row-end: 2; / 如果只佔一行或一列,grid-xx-end屬性可以不用寫 /

/ 等同於下面的程式碼 / grid-area: 1 / 1 / 2 / 4; / 這裡的順序是:row-start / column-start / row-end / column-end / } .grid-box-3 > div:nth-of-type(2) { grid-row: 2 / 4; / grid-row 是 grid-row-start 和 grid-row-end的縮寫 / } .grid-box-3 > div:nth-of-type(3) { grid-column: 2 / span 2; / span表示佔據幾行,這裡表示從2開始,佔據2行,也就是網格線2到4 / } .grid-box-3 > div:nth-of-type(6) { grid-column: 1 / span 3; } ```

網格單元和網格間距

一個網格單元是在一個網格元素中最小的單位,比如上面的例子中,4行3列,那麼網格佈局的父元素就被劃分成4*3=12個網格單元,子級元素將會排列在每個事先定義好的網格單元中。網格元素可以向行或著列的方向擴充套件一個或多個單元,並且會建立一個網格區域。網格區域的形狀應該是一個矩形(也就是說你不可能創建出一個類似於“L”形的網格區域)。

網格單元之間可以通過grid-column-gapgrid-row-gap或者grid-gap設定網格間距。下面的例子就是把網格列間距設定為2px,網格行間距設定為6px。

現在好像是改成column-gaprow-gapgap了。gap的順序是row-gap column-gapcss .grid-box-4 { /* 等同於 gap: 6px 2px; */ grid-column-gap: 2px; grid-row-gap: 6px; }

Grid佈局細節

使用repeat設定行列

我們再設定行列時,會遇到很多列的情況,如果一列一列去指定,太麻煩了。這個時候我們可以通過repeat函式來設定。 css .grid-box-6 { /* 等同於 grid-template-columns: 1fr 1fr 1fr; */ grid-template-columns: repeat(3, 1fr); }

不確定容器尺寸下的自動填充

有的時候,父容器的尺寸是不確定的,我們需要把子元素往父容器中逐個填充,這個時候我們可以利用auto-fillgrid-template-columns: repeat(auto-fill, 50px);表示,每一列都是50px,但是具體有幾列,需要根據子元素填充的情況來定。能放下8列,就放8列,不夠9列的部分空白。

css /* Grid 容器尺寸不固定,自動適配子元素 */ .grid-box-6 { border: 1px solid #999; display: grid; margin: 20px; grid-template-columns: repeat(auto-fill, 50px); } .grid-box-6 > div { height: 50px; background-color: bisque; border-radius: 4px; border: 1px solid #ccc; }

如果不希望後面有空白呢,這個時候就需要子節點有適當的寬度適配。子節點不再是固定寬度,而是通過minmax函式指定最小值。如果容器的行不夠整數,那麼就按照1:1的比例去適當增寬子節點。 css .grid-box-6 { grid-template-columns: repeat(auto-fill, minmax(50px, 1fr)) ; }

網格專案重疊

上面講到,每一個網格專案都可以指定佔據的網格單元。如果多個網格專案佔據同一個網格單元呢。比如上面的例子,網格專案1和網格專案2都需要佔據左上角這個網格單元。效果會是下面這樣:

我們會發現是2蓋住了1, 按照先後順序,預設情況是後面的DOM節點蓋住前面的DOM節點。不過我們可以通過設定z-index來改變覆蓋順序。

css .grid-box-5 > div:nth-of-type(1) { z-index: 2; }

網格線的命名

雖然我們可以通過指定網格線來確定網格區域,但是網格線還是太不直觀了。接下來我們講一講怎麼通過對網格線命名來解決這個問題。使用Chrome Dev Tools佈局檢視,可以看到命名的網格線名字。

css .grid-box-7 { grid-template-columns: [main-start] 1fr [content-start] 1fr [content-end] 1fr [main-end]; grid-template-rows: [main-start] 40px [content-start] 40px [content-end] 40px [main-end]; } .grid-box-7 > div:nth-of-type(1) { grid-column-start: main-start; grid-column-end: main-end; grid-row-start: main-start; grid-row-end: content-start; } .grid-box-7 > div:nth-of-type(2) { grid-column: main-start / content-start; grid-row: content-start / main-end; }

網格模板區域

雖然可以指定網格線的名字,但是網格線用起來還是不夠方便,Grid佈局提供了一個模板區域的設定方法。 網格專案中的屬性grid-area會指定當前網格專案的名字,在網格容器中的屬性grid-template-areas會通過引數中的名字, 設定對應網格專案的位置和所佔空間,其中.表示1fr的空白。 css .grid-box-8 { border: 1px solid #999; width: 400px; height: 120px; margin: 20px; display: grid; grid-template-columns: repeat(9, 1fr); grid-template-areas: "hd hd hd hd hd hd hd hd hd" "sd sd sd main main main main . ." "sd sd sd ft ft ft ft ft ft"; } .grid-box-8 > div { background-color: bisque; border-radius: 4px; border: 1px solid #ccc; } .grid-box-8 > div:nth-of-type(1){ grid-area: hd; } .grid-box-8 > div:nth-of-type(2){ grid-area: ft; } .grid-box-8 > div:nth-of-type(3) { grid-area: main; } .grid-box-8 > div:nth-of-type(4) { grid-area: sd; }

填充缺口

有的場景下,由於子元素寬度的不確定性,會出現空格,前面通過了grid-template-columns: repeat(auto-fill, minmax(50px, 1fr))解決了部分情況。但是如果網格專案的寬度是不變的,但是順序可變。這個時候,我們就可以通過grid-auto-flow來解決。

grid-auto-flow是控制自動佈局演算法怎樣運作的屬性,它能精確指定在網格中被自動佈局的元素怎樣排列。它有3個屬性值:column``,row(預設),dense。可以看出來,如果是columns網格專案就是先把一列排滿,再填如第二列。row就是先填滿一行,因為這個是預設值,所以前面的例子都是先填滿一行,再填下一行。

那這裡的dense呢,它指定自動佈局演算法使用一種“稠密”堆積演算法,如果後面出現了稍小的元素,則會試圖去填充網格中前面留下的空白。這樣做會填上稍大元素留下的空白,但同時也可能導致原來出現的次序被打亂。

這樣我們就可以利用grid-auto-flow: dense來解決空白問題。(不能完美解決,只能讓空白變小。)

比如下面這個例子,第一個子節點佔了三列,第二個子節點佔了2列,那麼第一行就會空一個。添加了grid-auto-flow: row dense後,就能自動匹配能填充到這個空間的子節點。(grid-auto-flow: dense也是同樣的效果)

css .grid-box-9 { width: 200px; display: grid; gap: 2px; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 50px; /* grid-auto-flow: row dense; */ } .grid-box-9 > div:nth-of-type(1){ grid-column-end: span 3; } .grid-box-9 > div:nth-of-type(2n){ grid-column-end: span 2; grid-row-end: span 2; }

元素的對齊

和flex類似,Grid佈局有以下容器屬性用於對齊:justify-contentjustify-itemalign-contentalign-item,另外,Grid還增加了place-contentplace-item用於縮寫。子元素也有三個用於對齊屬性:justify-selfalign-selfplace-self

簡單記憶:justify是在垂直方向對齊方式,align是水平方向對齊對齊,place是前面兩個屬性的縮寫,先alignjustifycontent是容器子元素的對齊,item是子元素所在自己空間的對齊;self是子元素的屬性,用於覆蓋父容器對應的item樣式。

justify-items: 垂直方向(列維度)的子元素在自己空間的對齊

align-items: 水平方向(行維度)的子元素在自己空間的對齊

justify-content: 垂直方向上,子元素在容器空間中的對齊

align-content: 水平方向上,子元素在容器空間中的對齊

justify-self 和 align-self

justify-self:子元素屬性,垂直方向上的對齊方式,覆蓋父元素中justify-items的值。具體的值和效果,同justify-items

align-self: 子元素屬性,水平方向上的對齊方式,覆蓋父元素中align-items的值。具體的值和效果,同align-items

容器屬性

| 屬性名 | 說明 | 屬性值 | |:-- |:-- |:-- | | grid-template-rows
grid-template-columns | 是基於網格行或者網格列的維度,去定義網格線的名稱和網格軌道的尺寸大小。
grid-template-rows:設定行
grid-template-columns:設定列 | grid-template-rows:基於網格行的軌道。
grid-template-columns:基於網格列的軌道。 none:這個關鍵字表示不明確的網格。所有的行和其大小都將由grid-auto-rows屬性隱式的指定。
長度:非負值的長度大小。px,rem,百分比等。
fr:非負值,用單位 fr 來定義網格軌道大小的彈性係數。
minmax函式: 表示當前網格軌道的最大最小值。minmax(auto, 100px)表示最大值100px,自動最小值。
max-content:表示以網格項的最大的內容來佔據網格軌道。
min-content:表示以網格項的最小的內容來佔據網格軌道。
auto:如果該網格軌道為最大時,該屬性等同於 max-content,為最小時,則等同於min-content。
fit-content函式:盒子會使用可用的空間,但永遠不會超過max-content。
repeat函式:表示網格軌道的重複部分,以一種更簡潔的方式去表示大量而且重複行的表示式。 | | grid-auto-rows
grid-auto-columns | 指定隱式建立的行軌道大小。
grid-auto-rows:隱式行的大小。
grid-auto-columns:隱式列的大小。 | 長度:px,百分比等。
fr:非負值,用單位 fr 來定義網格軌道大小的彈性係數。
minmax函式:表示當前網格軌道的最大最小值。minmax(auto, 100px)表示最大值100px,自動最小值。
max-content:表示以網格項的最大的內容來佔據網格軌道。
min-content:表示以網格項的最小的內容來佔據網格軌道。
auto:如果該網格軌道為最大時,該屬性等同於 max-content,為最小時,則等同於min-content。 | grid-template-areas | 需要和網格佈局容器的子元素的grid-area屬性配合使用。參考上文中的“網格模板區域”小節。指定當前網格容器的子元素的網格區域。不能有L型區域或者分散的同名區域。 | 多個字串:每一個給定的字串會生成一行,一個字串中用空格分隔的每一個單元會生成一列。多個同名的,跨越相鄰行或列的單元稱為網格區塊。非矩形的網格區塊是無效的。 | | grid-template | CSS屬性簡寫。包含了grid-template-rows,grid-template-columns,grid-template-areas | grid-template-rows / grid-template-columns : 同時指定網格行和網格列。比如:100px 1fr / 50px 1fr 2fr表示2行3列。
網格區域 + 行 / 列。 | | grid-auto-flow | 控制著自動佈局演算法怎樣運作,精確指定在網格中被自動佈局的元素怎樣排列。 | row:指定自動佈局演算法按照通過逐行填充來排列元素,在必要時增加新行。
column:指定自動佈局演算法通過逐列填充來排列元素,在必要時增加新列。
dense:指定自動佈局演算法使用一種“稠密”堆積演算法,如果後面出現了稍小的元素,則會試圖去填充網格中前面留下的空白。這樣做會填上稍大元素留下的空白,但同時也可能導致原來出現的次序被打亂。
row dense:行優先的“稠密”堆積演算法。
column dense:列優先的行有限的“稠密”堆積演算法。 | | grid-row-gap
row-gap | 指定網格行的間距。 | 長度:px,百分比等。 | | grid-column-gap
column-gap | 指定網格列的間距。 | 長度:px,百分比等。 | | grid-gap
gap | 指定網格行列的間距。會有兩個值,第一個是行間距,第二個是列間距。如果沒有列間距,那麼表示列間距和行間距一樣。 | 長度:px,百分比等。 | | grid | CSS屬性簡寫。包含了grid-templategrid-gapgrid-auto-flow。 | 值的組合方式有點複雜,不建議用吧,還是分開寫程式碼可讀性更好。 | | justify-items | 垂直方向(列維度)的子元素在自己空間的對齊 | start:對齊到最開始位置。
center:居中對齊
end:對齊到最末尾。
stretch:拉伸子元素到撐滿整個容器 | | align-items | 水平方向(行維度)的子元素在自己空間的對齊 | start:對齊到最開始位置。
center:居中對齊
end:對齊到最末尾。
stretch:拉伸子元素到撐滿整個容器
baseline:按照子元素的baseline對齊 | | place-items | justify-items和 align-items兩個的縮寫。先align-items再justify-items。 | | | justify-content | 垂直方向上,子元素在容器空間中的對齊 | start:對齊到最開始位置。
center:居中對齊
end:對齊到最末尾。
space-between:多餘空間平均分佈在子元素中間。
space-around:多餘空間平均環繞在子元素中間
space-evenly:多餘空間平均分佈子元素和容器邊框之間。
stretch:拉伸子元素到撐滿整個容器 | | align-content | 水平方向上,子元素在容器空間中的對齊 | 同justify-content | | place-content | justify-content和 align-content兩個的縮寫。先align-content再justify-content。 | |

專案屬性

| 屬性名 | 說明 | 屬性值 | |:-- |:-- |:-- | | grid-column-start
grid-column-end
grid-column | 指定當前網格區域的佔據的列範圍。
grid-column-start指定開始的網格線。
grid-column-end指定結束的網格線。
grid-column是前面兩個的縮寫。順序是<grid-column-start> / <grid-column-end> | 網格線:可以是網格線的數字,也可以是網格線的名字。
span:佔據的網格列個數。 比如span 3表示從當前列開始,佔據3列。| | grid-row-start
grid-row-end
grid-row | 指定當前網格區域的佔據的行範圍。
grid-column-start指定開始的網格線。
grid-column-end指定結束的網格線。
grid-column是前面兩個的縮寫。<grid-column-start> / <grid-column-end> | 網格線:可以是網格線的數字,也可以是網格線的名字。
span:佔據的網格行個數。 比如span 3表示從當前行開始,佔據3行。 | | grid-area | 指定專案放在哪一個區域。有兩種情況,
一種是指定名字,根據grid-template-area中的位置,進行指定。
另一種是指定網格線。| 名字:根據grid-template-area中的設定的位置,進行定位。
網格線:指定4根網格線來確定網格區域。比如:1 / 2 / 3 / 4。順序是:grid-row-startgrid-column-startgrid-row-endgrid-column-end。 | | justify-self | 當前元素的垂直對齊方式。用於覆蓋父容器指定的justify-items | start:對齊到最開始位置。
center:居中對齊
end:對齊到最末尾。
stretch:拉伸子元素到撐滿整個容器 | | align-self | 當前元素的水平對齊方式。用於覆蓋父容器指定的align-items | start:對齊到最開始位置。
center:居中對齊
end:對齊到最末尾。
stretch:拉伸子元素到撐滿整個容器
baseline:按照子元素的baseline對齊 | | place-self | justify-selfalign-self兩個的縮寫。先align-selfjustify-self。 | |

總結

Grid的內容有點多,這一篇整理了概念和屬性,算是“理論”篇,後面會再寫一篇Grid的例子,當作“實踐”篇。如果覺得學了不知道用在哪裡的,可以關注下。

結束

好了,本文到此結束,希望本文對你有所幫助 :-) 最近新弄了一個公眾號:寫程式碼的浩,求關注 😄。後面會逐步把掌握的前端知識以及職場知識沉澱下來。 如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。