# Grid

CSS grid layout，又称 CSS grid 或 grid，是一种基于二维网格的布局系统，它擅长将页面划分成行和列。

和 table 一样，grid 也能让元素对齐到 row 和 column 中。但 grid 能更容易地实现更多其它布局，比如它的子元素可以 position（定位）自己，即子容器实际上是 overlap（重叠）和 layer（分层）的，类似于 CSS 的 positioned elements（定位元素）。

和 flexbox 类似，grid items 的 order 也能通过 CSS 来设置，好处是可以用 media query 来灵活摆放。

## 1. 相关术语

1. grid container：设置了 `display: grid` 的元素
2. grid item：是 grid container 的（直接）子元素
3. grid line：是构成 gird 结构的 dividing lines，位于行或列的任意一侧
   * 可以是 vertical 的 column grid lines
   * 也可以是 horizontal 的 row grid lines
4. grid track：两条相邻 grid lines 之间的空间。可以视为 grid 的 row 或 column
5. grid area：被四条 grid lines 围起来的总空间。可能是由多个 grid cells 组成的
6. grid cell：被两条相邻 row grid lines 和两条相邻 column grid lines 围起来的空间。它是 grid 的 unit

<figure><img src="https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2Fe2TeI8lvgKv90ATvgvhE%2Fimage.png?alt=media&#x26;token=1a44a551-2c31-4a1c-8d5c-7ad82592bcec" alt=""><figcaption></figcaption></figure>

## 2. container 属性

### 2.1 `display`

定义了一个 grid container，为其内容建立了一个新的 grid formatting context（grid 格式化上下文）。

```css
display: grid;         /* block-level grid */
display: inline-grid;  /* inline-level grid */
```

### 2.2 行和列

#### 2.2.1 “布局”行和列

* `grid-template-columns`
* `grid-template-rows`

以上两个属性用“以空格分隔的 values 列表”的形式定义了 grid 的 columns 和 rows，其中 value 是 track size 的值，它们之间的空间就是 grid line。

value 的取值可以是：`<track-size>`, `<line-name>`。

**（1）`<track-size>`**

```css
/* 列 */
grid-template-columns: 1fr 1fr 1fr;    /* fr: a fraction of the free space */
grid-template-columns: repeat(3, 1fr); /* 效果同上 */
grid-template-columns: 50px 1fr 100px; /* <length> */
grid-template-columns: 10% 1fr 30%;

/* 行 */
grid-template-rows: 1fr 1fr;
```

**（2）`<line-name>`**

grid lines 会被自动分配对应的数字，正序是从 1 到 n，倒序是从 -1 到 -n。如下：

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FlYnZRfFGoeBE5niCxXr1%2Fimage.png?alt=media\&token=ebf7a0d8-e6c6-4d41-b912-b4e23241cf97)

也可以给 grid lines 命名。比如：

```css
/* grid lines 用默认编号 */
grid-template-columns: 40px 50px auto 50px 40px;

/* 给 grid lines 命名 `[]` */
grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end];

/* 给一个 grid line 命多个名字 `[?-?]` */
grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line];
```

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FhLNycgBbdA8CuEUsMqEV%2Fimage.png?alt=media\&token=d2a752ef-235e-4be4-8c92-4f3094457228)

如果设置的 `<line-name>` 是重复的，可以用 `repeat()` 简化下。比如：

```css
grid-template-columns: 20px [col-start] 20px [col-start] 20px [col-start];
grid-template-columns: repeat(3, 20px [col-start]);
```

上面代码的多个 grid lines 有相同的名字，如果想引用某个 line，可以用 line name 和 count。比如：

```css
grid-column-start: col-start 2;
```

#### 2.2.2 给行和列“贴瓷砖”

`grid-template-areas` 定义了一个 grid template，通过引用“子容器”的 `grid-area` 属性指定的 grid area 的 name。

`grid-template-areas` 本身就提供了 grid structure 的可视化。看个例子：

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FgyWZPye8hhv7X9OAwt6L%2Fimage.png?alt=media\&token=c1dbab90-41b7-456e-8a4b-e3bb5fa9f961)

```css
/* 父容器 */
.grid {
    display: grid;
    /* 会创建一个 4 列 3 行的 grid */
    grid-template-areas:
        "header header header header" /* 重复的 grid-area name 会让内容横跨这些 cells */
        "main main . sidebar"         /* . 表示 empty cell */
        "footer footer footer footer";
}

/* 子容器 */
.grid>div:nth-child(1) {
    grid-area: header;
    background-color: orange;
}

.grid>div:nth-child(2) {
    grid-area: main;
    background-color: deepskyblue;
}

.grid>div:nth-child(3) {
    grid-area: sidebar;
    background-color: pink;
}

.grid>div:nth-child(4) {
    grid-area: footer;
    background-color: green;
}
```

关于 `grid-template-areas` 属性的相关说明：

1. 每个 row 必须有相同数量的 cells，否则该声明会失效
2. 连续的多个 `.` 只代表一个 empty cell，除非它们之间有“空格”分隔符
3. 它不 name（命名）grid lines，只 name（命名）areas，虽然此时 area 两端的 lines 会被自动命名。比如 grid area 是 `foo`，那么该 area 起始的 row line 和 column line 都叫 `foo-start`，最后的 lines 都叫 `foo-end`。这就意味着，有的 line 可能会有多个名字，比如上例中最左侧的 line 有三个名字 `header-start`, `main-start`, `footer-start`
4. 当它设置的 column 的数量和 `grid-template-columns` 的个数不一致时
   * 优先取 `grid-template-columns` 的值
   * 若 `grid-template-areas` 少了，就用其它子容器补齐
   * 若 `grid-template-areas` 多了，则多出来的子容器 `width:auto`（整体会保证列对齐）
5. 可以这样理解：
   * `grid-template-columns/rows` 负责 layout（布局）
   * `grid-template-areas` 负责 span（平铺/贯穿/横跨）

<figure><img src="https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FeNYHhQox0EUqhwwpwJim%2Fimage.png?alt=media&#x26;token=b9ed7346-d956-4efa-aa06-2624b129bd51" alt=""><figcaption><p>当 grid-template-columns 值更大时，取它</p></figcaption></figure>

<figure><img src="https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2F4uA6tzHNAIuMzKn1PQyY%2Fimage.png?alt=media&#x26;token=42f5a5cc-74c5-4a6d-8786-cc3f0f1e25c3" alt=""><figcaption><p>当 grid-template-columns 值更小时，若子没 width 则相当于不存在</p></figcaption></figure>

<figure><img src="https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FMljbZ4MS5Oh9ZNfnjJdK%2Fimage.png?alt=media&#x26;token=2f7177f5-0bab-47e3-ae58-72378bdca25e" alt=""><figcaption><p>当 grid-template-columns 值更小时，grid-template-area 多出来的列 width 是 auto</p></figcaption></figure>

#### 2.2.3 属性缩写

`grid-template` 是以上三个属性的缩写，格式是：

```css
<grid-template-areas> <grid-template-rows> / <grid-template-columns>
```

看几个例子，代码如下：

```css
grid-template: 
            "a a a" 40px
            "b c c" 40px
            "b c c" 40px / 1fr 1fr 1fr;

grid-template: 
            "b b a" auto
            "b b c" 2ch
            "b b c" 1em / 20% 20px 1fr;

grid-template: 
            "a a ." minmax(50px, auto)
            "a a ." 80px
            "b b c" auto / 2em 3em auto;
```

以上代码，会依次显示下面的布局：

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FrqY2OtrAfIPa7Sr3Sgc7%2Fimage.png?alt=media\&token=fd22a337-4209-4f1a-bf5c-0e927d264662)

相关说明：

1. 格式 `<grid-template-rows> / <grid-template-columns>`  会把 `grid-template-areas` 设置成 `none`
2. 当设置 `grid-template: none` 时，表示这三个属性的值都是它们的 initial values。也就是说，`grid-template` 不会隐式重置 grid properties，而通常写 `none` 都是想 reset 各个属性的值。所以，与缩写相比，更推荐用单个属性
3. 此外，个人的使用感受是：不推荐用缩写。一是功能上杂糅了对 rows 和 columns 的“布局”和“贴片”，二是视觉上也怪眼花缭乱的...

### 2.3 分配“整体”的剩余空间

有时，内容的总 size 会比 grid container 的小，此时就可以用以下属性设置 grid 在 row 或 column 上的对齐。

1. `justify-content`：在 row axis 上分配剩余空间
2. `align-content`：在 column axis 上分配剩余空间
3. `place-content` 缩写：`<align-content> / <justify-content>`

取值可以是：

* `start`, `end`, `center`
* `stretch`
* `space-around`, `space-between`, `space-evenly`

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FuEbDhD5nHtYxjj58CGJ6%2Fimage.png?alt=media\&token=ad54eea8-148f-4ae1-8f87-c616644d441e)![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FKPhN4zVrsiyR4LgrOP7H%2Fimage.png?alt=media\&token=45ddf37e-e3f7-4611-8407-15d847cb8350)

### 2.4 cell 内沿 axis 的对齐

用来设置 grid items 在 grid cell 里沿 row axis 或 column axis 的对齐。

1. `justify-items`
2. `align-items`
3. `place-items` 缩写：`<align-items> / <justify-items>`

取值可以是：

* 公共取值：`start`, `end`, `center`, `stretch`
* `baseline`：`align-items` 属性时

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2Fa32Ytjhc4hoiCGWHHuSJ%2Fimage.png?alt=media\&token=ffc9b168-a06c-48a2-8c7d-5246ffb48c04)

### 2.5 间隔

指定 grid line 的 size，可以视作是 columns 之间或 rows 之间的 gutter（间距）with，不含外边缘。

1. `row-gap`
2. `column-gap`
3. `gap` 缩写：`<row-gap> <column-gap>`

```css
/* standard */
row-gap: 15px;
column-gap: 10px;
gap: 15px 10px;

/* 旧用法 */
grid-row-gap: 15px;
grid-column-gap: 10px;
grid-gap: 15px 10px;
```

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FZmbhYGVf7ZFIPP2Jcpyk%2Fimage.png?alt=media\&token=408f3a23-4062-4560-8be5-1b945b1947e5)

### 2.6 指定隐式创建的 track size

`grid-auto-colums` 指定隐式创建的 track size。

隐式创建，也称自动生成。当 grid items 多于 grid cells 时，或当一个 grid item 放在了显式 grid 之外时，就会创建隐式 track。这样做的好处是，让 grid 更灵活地摆放它的 items，因为我们可以不必（显式地）指定每个 track，也不必手动放置每个 item。显式指定 track 的属性有 `grid-template-rows` 和 `grid-template-columns`。

通过两个例子，感受下增加了 `grid-auto-colums` 属性之后的 UI。如下：

<figure><img src="https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FEU28Ws5Fd7ffI0Xg0C8R%2Fimage.png?alt=media&#x26;token=dc7bf237-6a57-422f-b7aa-b83c81a472b4" alt=""><figcaption></figcaption></figure>

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FtjUIt7lvF9xuraRWjsZV%2Fimage.png?alt=media\&token=04ac3b80-78a6-40f7-9861-dd9f90a17ef0)

说明：

* `grid-column: 5 / 6` 表示从 column line 5 到 column line 6
* `grid-row: 2 / 3` 表示从 row line 2 到 row line 3

### 2.7 有隐式 track 时如何放置 items

当有创建隐式 track 时，就会启动 auto-placement algorithm（自动放置算法）来布局 items。`grid-auto-flow` 属性就是用来控制该算法的工作方式的，它可以指定 items 如何流入 grid。

取值可以是：

* `row`（默认）：依次填充每 row，并根据需要添加新 row
* `column`：依次填充每 column，并根据需要添加新 column
* `dense`：如果后面有更小的 items 来了，则尝试更早地填充 grid holes

> 1. 单词“dense”：密集的，稠密的
>    * dense 算法，会回溯找能填的 holes，所以 items 可能会乱序
> 2. 单词“sparse”：稀少的，稀疏的
>    * sparse 算法，只向前移动 items，但从来不回溯，所以 items 是有序的

看个例子：

```css
.container {
    display: grid;
    grid-template-columns: repeat(5, 60px);
    grid-template-rows: repeat(2, 30px);
}
.item:nth-child(1) {
    grid-column: 1;
    grid-row: 1 / 3;
}
.item:nth-child(5) {
    grid-column: 5;
    grid-row: 1 / 3;
}
```

当分别设置 `grid-auto-flow` 的值是 `row` 和 `column` 时，items 的布局依次如下图：

```css
.container {
    grid-auto-flow: row;
}

.container {
    grid-auto-flow: column;
}
```

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FhpeaYZAuKBonbk8bUa0j%2Fimage.png?alt=media\&token=10cece06-c0b0-482c-ba38-f36f5ce7d80d)

### 2.8 `grid` 缩写

`grid` 是个缩写属性，用来设置所有 explicit（显式）和 implicit（隐式）的 grid 属性。

1. grid-template-rows
2. grid-template-columns
3. grid-template-areas
4. grid-auto-rows
5. grid-auto-columns
6. grid-auto-flow

缩写的属性值的形式看起来挺费劲的，这里就不展开介绍了，等把单个属性用熟练了再补充。

## 3. items 属性

### 3.1 放置和堆叠

通过引用特定的 grid lines 来确定 grid item 的位置。

当 items 之间相互重叠时，可以使用 `z-index` 控制它们的堆叠顺序。如果没有指定 `grid-xxx-end`，则 item 默认会跨 1 个 track。

1. `grid-column-start`
2. `grid-column-end`
3. `grid-row-start`
4. `grid-row-end`
5. `grid-column` 缩写：`<grid-column-start> / <grid-column-end>`
6. `grid-row` 缩写：`<grid-row-start> / <grid-row-end>`

#### eg1. 使用默认编号的 grid line

```css
grid-column-start: 2;
grid-column-end: 4;      /* 从 line2 到 line4（实际跨了2列） */
grid-column-end: span 3; /* 从 line2 开始，跨 3 列 */
```

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FlYnZRfFGoeBE5niCxXr1%2Fimage.png?alt=media\&token=ebf7a0d8-e6c6-4d41-b912-b4e23241cf97)

#### eg2. 命名的 grid line

```css
/* 图左 */
.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;
}
```

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2Fyl0wjqfsF0CPO9V6ACte%2Fimage.png?alt=media\&token=d842b51a-9e45-4642-9722-ff00a86ed4c5)![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2F7HA3isUTNNWWRNI19Ujs%2Fimage.png?alt=media\&token=3a4252a7-0cc6-49c7-99e5-b07c68861ccb)

#### eg3. 缩写

```css
.item-c {
  grid-column: 3 / span 2;
  grid-row: third-line / 4;
}
```

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2F1q2z72JUDXckzkXAEYwJ%2Fimage.png?alt=media\&token=f2c968ba-09ea-4c83-a03f-417c039bbd51)

### 3.2 给 item 命名

`grid-area` 属性可以给 item 一个名字，以便被 [`grid-template-areas`](#2.2.2-gei-hang-he-lie-tie-ci-zhuan) 属性引用。

```css
grid-area: header;
grid-area: main;
grid-area: sidebar;
grid-area: footer;
```

`grid-area` 属性也可以用作更短的缩写。

<pre class="language-css"><code class="lang-css"><strong>/* &#x3C;grid-row-start> / &#x3C;grid-column-start> / &#x3C;grid-row-end> / &#x3C;grid-column-end> */
</strong>grid-area: 1 / col4-start / last-line / 6;
</code></pre>

![](https://2598460105-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FGNkDWo1TzHEOBRUxCRfy%2Fuploads%2FfaVA0HPGSCrRXqSUaLno%2Fimage.png?alt=media\&token=331dd477-28e2-4029-921c-ad0c2780c06d)

### 3.3 cell 内沿 axis 的对齐

设置本 item 在单个 grid cell 里沿 row axis 或 column axis 的对齐方式

1. `justify-self`
2. `align-self`
3. `place-self` 缩写：`<align-self> / <justify-self>`

作用同父容器的[在 cell 内沿 axis 对齐](#2.4-cell-nei-yan-axis-de-dui-qi)，只是这三个属性只控制本 item。

## 主要参考

* <https://css-tricks.com/snippets/css/complete-guide-grid/>
