CSS-Grid

整理 Grid 的排版與範例

前言

在 Youtube 看 Amos 大大 解說 Grid 的各種屬性及運用,所以將一些使用方式及技巧做個紀錄。


CSS Grid

繼 Flexbox 之後,另一新品種的排版方式,

而主要排版可選「格子」或「線條」二種方式去分配區塊。


「格」的概念

定義好共有「幾列幾欄」後,再依照有幾個區塊,分別要放置哪個地方。

分配放置的結果,如下所示


父層

grid-template-rows:設定幾
grid-template-columns:設定幾
grid-template-areas:分配各區塊佔據的位置

子層

grid-area:佔據的名稱

範例

HTML
1
2
3
4
5
<div class="container">
<div class="box1">A</div>
<div class="box2">B</div>
<div class="box3">C</div>
</div>
CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.container {
width: 100%;
height: 400px;
outline: 2px solid red;
display: grid;
grid-template-rows: 1fr 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-areas:
'B3 B3 B1 B1'
'B3 B3 B1 B1'
'B3 B3 B1 B1'
'B2 B2 B2 B2';
}

.container {
font-size: 50px;
}

.box1 {
grid-area: B1;
background-color: #faa;
}
.box2 {
grid-area: B2;
background-color: #afa;
}
.box3 {
grid-area: B3;
background-color: #aaf;
}

範例程式:JSBin


grid-template-areas 須為連續區塊

在分配區塊的位置時,須為連續矩形區塊,不可有「交叉、L 形」之類的分配。

正確

錯誤

B3區塊這樣設定的話,就會造成 Grid 壞掉


新單位 fr(fractional)

原本我們分配rowscolumns時,單位都是使用px%…等,
而 Grid 有提供一個新單位fr, 他的概念就像「幾分之幾」一樣,
下列用範例說明解釋

範例說明

CSS
1
grid-template-rows: 1fr 1fr 2fr 1fr;

先將全部的 fr 加總,所以共有 5fr,然後上例共分成四個區塊,

所以分別佔據的面積就為 1/51/52/51/5


repeat

如果分配的區塊都相同或者有一定的規則時,這樣我們就可以用 repeat 來重覆定義。

CSS
1
2
3
grid-template-rows: repeat(4, 1fr);
/* 等同下例 */
grid-template-rows: 1fr 1fr 1fr 1fr;

也可以多個。

CSS
1
2
3
grid-template-rows: repeat(2, 1fr 2fr);
/* 等同下例 */
grid-template-rows: 1fr 2fr 1fr 2fr;

grid-gap 格線

簡單來說,就是設定每個區塊上下左右之間,是否有空隙

另外如果有設定grid-gap時,整個區塊的空間會先分配給grid-gap後,

剩餘的空間,再給fr去做切割使用。

語法

grid-gap: 列row / 欄column;

也可分別設定的,

grid-row-gap: 列row;

grid-column-gap: 欄column;

範例

HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="grid-container">
<div class="item1">1</div>
<div class="item2">2</div>
<div class="item3">3</div>
<div class="item4">4</div>
<div class="item5">5</div>
<div class="item6">6</div>
<div class="item7">7</div>
<div class="item8">8</div>
<div class="item9">9</div>
<div class="item10">10</div>
<div class="item11">11</div>
<div class="item12">12</div>
</div>
CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.grid-container {
display: grid;
grid-template-columns: auto auto auto auto;

grid-gap: 30px 5px; /* 列 欄 */

background-color: #2196f3;
padding: 10px;
}

.grid-container > div {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 20px 0;
font-size: 30px;
}

範例程式:JSBin


「線」的概念

我們一樣切割為「四欄四列」,而「面的概念」是用佔據第幾個區塊來分配,

不過「線」的話,就是用「起始線/終點線」來規劃佔據的範圍到哪裡,

再說三次,線的概念為

起始線/終點線
起始線/終點線
起始線/終點線

範例

用上面「面的範例」來修改,註解掉的地方為「面的寫法」,

改用「線的寫法」,來呈現一樣結果。

CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
.container {
width: 100%;
height: 400px;
outline: 2px solid red;
display: grid;

grid-template-rows: 1fr 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr 1fr;

/*
grid-template-areas:
'B3 B3 B1 B1'
'B3 B3 B1 B1'
'B3 B3 B1 B1'
'B2 B2 B2 B2'; */
}

.container {
font-size: 50px;
}

.box1 {
/* grid-area: B1; */

grid-column: 3/5;
grid-row: 1/4;
background-color: #faa;
}
.box2 {
/* grid-area: B2; */

grid-column: 1/5;
grid-row: 4/5;
background-color: #afa;
}
.box3 {
/* grid-area: B3; */

grid-column: 1/3;
grid-row: 1/4;
background-color: #aaf;
}

範例程式:JSBin


線的分配可為「負值」

線的分配設定值為:起始線/終點線,不過裡面的值可為「負數」,

代表從尾段往前計算線條位置。

範例

1
2
3
4
5
6
7
8
9
10
.box1 {
/* A 區塊 */
grid-row: 1/5;
grid-column: 4/5;
}
.box2 {
/* B 區塊 */
grid-row: 5/-5;
grid-column: 1/-4;
}

範例程式:JSBin


span 的用法

前面我們說「線」的分配設定值為:起始線/終點線,其實也可以配合「span」來使用。
不過使用span時,要特別注意二點

  1. span的值,只能 正數
  2. span的方向,都是 由左至右、由上而下

不過第二點比較容易踩雷,所以再說三次

由左至右、由上而下
由左至右、由上而下
由左至右、由上而下

範例

以此圖來說,我想要 A、B 二區塊,從上而下全部佔滿,

這時除了使用 起始線/終點線 的寫法外,

我可以使用 span 來表示要佔據幾格。

CSS
1
2
3
4
5
6
7
8
9
10
11
.box1 {
/* A 區塊 */
grid-row: 1/ 5;
grid-column: 4/5;
}

.box2 {
/* B 區塊 */
grid-row: 1 / span 4; /* 使用span用法 */
grid-column: 1/-4;
}

從上例來看 .box2grid-row: 1/ span 4;
就是從 起始線 1 的位置 開始佔據 4 格 的空間。

範例程式:JSBin


特殊分配法

介紹完「面與線」的概念後,再來我們先來個簡單又特別的範例,

範例

下例切割為「八列八欄」,共有 ABCD 區塊要分配,我們要排成一個斜線的形狀。

HTML
1
2
3
4
5
6
<div class="container">
<div class="box1">A</div>
<div class="box2">B</div>
<div class="box3">C</div>
<div class="box4">D</div>
</div>
CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
.container {
width: 100%;
height: 400px;
outline: 2px solid red;
display: grid;

grid-template-rows: repeat(8, 1fr);
grid-template-columns: repeat(8, 1fr);
}

.container {
font-size: 50px;
}

.box1 {
grid-row: 1/3;
grid-column: 1/3;
background-color: #faa;
}
.box2 {
grid-row: 3/5;
grid-column: 3/5;
background-color: #afa;
}

.box3 {
grid-row: 5/7;
grid-column: 5/7;
background-color: #aaf;
}

.box4 {
grid-row: 7/9;
grid-column: 7/9;
background-color: #8f8;
}

範例程式:JSBin


可「重疊」分配

再用上例來修改,如果想要 C 的部份區塊要蓋在 B 區塊上面,只要將二者分配的值,有交錯即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ...略

.box2 {
grid-row: 3/5;
grid-column: 3/5;
background-color: #afa;
}

.box3 {
grid-row: 4/7;
grid-column: 4/7;
background-color: #aaf;
}

// ...略

範例程式:JSBin

補充說明:
如果想要換成 B 蓋在 C 上面的話,就可以使用 positionz-index 配合使用,
不過在 Grid 裡,可以直接使用 z-index 即可。

grid-auto-* 自動切割欄列

1
2
3
4
5
6
7
// 固定分配
grid-template-rows: repeat(8, 1fr);
grid-template-columns: repeat(8, 1fr);

// 自動分配
grid-auto-rows: 1fr;
grid-auto-columns: 1fr;

再來我們來說說,grid-template-*grid-auto-* 之間差異點,

就是 grid-auto-* 會自動計算你使用的正整數最大值後,自動用最大值去切割區塊,

這樣可能還不是很清楚,我們用範例來說明:

範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.container {
display: grid;

grid-auto-rows: 1fr;
grid-auto-columns: 1fr;
}

.box1 {
grid-row: 1/10;
grid-column: 1/2;
}
.box2 {
grid-row: 3/5;
grid-column: 1/8;
}

從上例來看的話,我們先看 rows 的部份,

.box1grid-row: 1/10;
.box2grid-row: 3/5;

上述row裡面最大正整數值為:10,

不過要注意 10終點線,所以要扣掉 1,共切了 9 格;

columns 的部份規則也是一樣,

.box1grid-column: 1/2;
.box2grid-column: 1/8;

上述columns裡面最大正整數值為:8,

所以 8 - 1 = 7 ,共切了 7 格。

範例程式:JSBin


minmax()

指定最小格線及最大格線。

範例:

HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="grid">
<div class="item">
<img src="https://fakeimg.pl/200x200/?text=Hello">
</div>
<div class="item">
<img src="https://fakeimg.pl/200x200/?text=Hello">
</div>

<!-- 圖片*100個 -->

<div class="item">
<img src="https://fakeimg.pl/200x200/?text=Hello">
</div>
</div>
CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
* {
margin: 0;
padding: 0;
}

.grid {
box-sizing: border-box;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}

.item {
outline: 1px solid red;
}

.item img {
width: 100%;
/* 解決baseline問題 */
vertical-align: top;
}

說明 minmax(160px, 1fr)

grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));

簡單說明一下,上述程式碼

auto-fill 就是自動填滿,那用 minmax(160px, 1fr) 填滿是什麼意思呢!

單單從 minmax(160px, 1fr) 這程式碼來描述的話,

最小值就是 160px ,而最大值是 1fr ??

1fr又代表多少呢?

讓我再用簡單例子來說明(給自己聽),

因為我本身設定最小值為160px,所以當我一列若要可以塞下第二個 div 的話,
我最少也要有 160px*2=320px 的寬度,才能塞得下第二個 div,
所以當一列的寬度在 160px~319px 時,只會有一個 div,
並且這一個 div 會在160px~319px 之間,自動幫我伸縮它的寬度,
但當我一列的寬度到達 320px 寬度時,它就會塞入第二個 div 在同一列上,
所以我大膽假設minmax(160px, 1fr)1fr,
就是取 最小值 * 2 - 1px 吧!

範例:

寬度:320px 時,一列可放 2 張圖片

寬度:480px 時,一列可放 3 張圖片

範例程式:JSBin


對齊方式