网格布局的基本概念 - CSS：层叠样式表

网格布局的基本概念
=========

CSS 网格布局引入了二维网格布局系统，可用于布局页面主要的区域或小型用户界面元素。本文介绍了 CSS 网格布局与 CSS 网格布局规范第 1 版中的新术语。这篇简介中所展示的每种特性，将在本指南的其余部分中详细介绍。

什么是网格？
------

网格是一组相交的水平线和垂直线，它定义了网格的列和行。我们可以将网格元素放置在与这些列和行相关的位置上。CSS 网格布局具有以下特点：

### 固定的位置和弹性的轨道的大小

你可以使用固定的轨道尺寸创建网格，比如使用像素单位。你也可以使用比如百分比或者专门为此目的创建的新单位 `fr` 来创建有弹性尺寸的网格。

### 网格项摆放

你可以使用行号、行名或者标定一个网格区域来精确定位元素。网格同时还使用一种算法来控制未给出明确网格位置的元素。

### 创建额外的轨道来包含内容

可以通过网格布局定义显式网格。网格布局规范非常灵活，可以在需要时添加额外的行和列。包括添加“一个容器能容纳的尽可能多的列”等特性。

### 对齐控制

网格包含对齐特性，因此我们可以控制项目放入网格区域后的对齐方式，以及整个网格的对齐方式。

### 控制重叠内容

多个项目可以放置在网格单元格中，或者区域可以部分地彼此重叠。然后可以使用 `z-index` 属性来控制重叠区域显示的优先级。

网格布局是一个强大的规范，当与 CSS 的其他部分（如弹性盒）结合使用时，可以帮助你创建以前不可能在 CSS 中构建的布局。这一切都是通过在**网格容器**上创建一个网格来开始的。

网格容器
----

我们通过在元素上声明 `display：grid` 或 `display：inline-grid` 来创建一个*网格容器*。一旦我们这样做，这个元素的所有*直系子元素*将成为*网格项目*。

在这个示例中，有一个类名为 `wrapper` 的 `div` 元素作为容器，其内部有五个子元素。

```html
<div class="wrapper">
  <div>一</div>
  <div>二</div>
  <div>三</div>
  <div>四</div>
  <div>五</div>
</div>
```

我将 `.wrapper` 作为一个网格容器。

```css
.wrapper {
  display: grid;
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

所有直系子元素现在都是网格项了。在 web 浏览器中，元素转为网格项前看不出什么差异，因为网格给这些元素创建了一个单列网格。此刻，Firefox 开发者版（Developer Edition）可能会助你一臂之力。此时，你可能会发现使用 Firefox 开发工具中的网格检查器非常有用。如果你在 Firefox 中查看此示例并检查网格，会看到 `grid` 值旁边有一个小图标。单击该图标后，该元素上的网格就会显示到浏览器窗口中。

![使用 DevTools 中的网格高亮器观察网格](/zh-CN/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout/1-grid-inspector.png)

当你学习并且使用 CSS 网格布局时，这个工具能让你更好地了解到你的网格在视觉上发生了哪些变化。

如果我们想让这个示例更加“网格化”，我们需要使用列轨道。

网格轨道
----

我们使用 `grid-template-rows` 和 `grid-template-columns` 属性定义网格上的行和列。这些属性定义了网格轨道。*网格轨道*（grid track）是网格上任意两条相邻线之间的空间。下图显示了一个突出显示的轨道——这是网格中第一行的轨道。

![一个包含 3 个网格项的方框。在这三个项目的上方有一个浅绿色的实心区域，这就是轨道。](/zh-CN/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout/1_grid_track.png)

通过使用 `grid-template-columns` 和 `grid-template-rows` 属性或简写的 `grid` 或 `grid-template` 属性，可在显式网格中定义网格轨道。在隐式网格中，也可以通过在显式网格中创建的轨道外定位网格项来创建轨道。

### 基本示例

我可以通过添加 `grid-template-columns` 属性将列轨道添加到之前的示例，然后定义列轨道的大小。

我现在创建了一个网格，包含了三个 200 像素宽的列轨道。子元素将在网格上每个网格单元中摆放。

```html
<div class="wrapper">
  <div>一</div>
  <div>二</div>
  <div>三</div>
  <div>四</div>
  <div>五</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: 200px 200px 200px;
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

### fr 单位

轨道可以使用任何长度单位进行定义。网格还引入了一个另外的长度单位来帮助我们创建灵活的网格轨道。新的 `fr` 单位代表网格容器中可用空间的一部分。下一个网格定义将创建三个等宽的轨道，并根据可用空间的大小进行增减。

```html
<div class="wrapper">
  <div>一</div>
  <div>二</div>
  <div>三</div>
  <div>四</div>
  <div>五</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

### 不同尺寸

在下面的这个示例中，我们定义了一个 `2fr` 轨道和两个 `1fr` 轨道。可用空间被四等分。其中两份给了第一个轨道，剩下两个轨道各占一份。

```html
<div class="wrapper">
  <div>一</div>
  <div>二</div>
  <div>三</div>
  <div>四</div>
  <div>五</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

### 混合弹性尺寸和绝对尺寸

在最后一个示例中，我们将绝对大小的轨道与 `fr` 单位混合使用。第一条轨道是 500 像素，因此从可用空间中扣除了固定宽度。剩下的空间被一分为三，并按比例分配给两个灵活的轨道。

```html
<div class="wrapper">
  <div>一</div>
  <div>二</div>
  <div>三</div>
  <div>四</div>
  <div>五</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: 500px 1fr 2fr;
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

### 在轨道列表中使用 repeat() 标记

包含多个轨道的大型网格可使用 `repeat()` 标记来重复部分或整个轨道列表。如下方的网格定义：

```css
.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}
```

也可写成：

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
```

Repeat 标记可以用于重复轨道列表中的一部分。在下面的示例中我创建了一个网格，其起始轨道为 20 像素，接着重复了 6 个 `1fr` 的轨道，最后再添加了一个 20 像素的轨道。

```css
.wrapper {
  display: grid;
  grid-template-columns: 20px repeat(6, 1fr) 20px;
}
```

Repeat 标记可以传入一个轨道列表，因此你可以用它来创建一个多轨道模式的重复轨道列表。在下一个示例中，网格将有共计 10 个轨道，为 1 个 `1fr` 轨道后面跟着 1 个 `2fr` 轨道，该模式重复 5 次。

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(5, 1fr 2fr);
}
```

### 隐式和显式网格

在创建示例网格时，我们使用 `grid-template-columns` 属性专门定义了列轨道，但网格也会自行创建行。这些行是隐式网格的一部分。而显式网格由使用 `grid-template-columns` 或 `grid-template-rows` 定义的任何行和列组成。

如果你在定义的网格外放置内容，或者由于内容太多，需要更多的网格轨道，那么网格就会在隐式网格中创建行和列。默认情况下，这些轨道会自动调整大小，因此它们的大小取决于轨道内的内容。

你还可以使用 `grid-auto-rows` 和 `grid-auto-columns` 属性为在隐式网格中创建的轨道定义设定大小。

在下面的示例中我们用 `grid-auto-rows` 属性来确保在隐式网格中创建的轨道是 200 像素高。

```html
<div class="wrapper">
  <div>一</div>
  <div>二</div>
  <div>三</div>
  <div>四</div>
  <div>五</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px;
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

### 轨道大小和 minmax

在设置显式网格或定义自动创建的行或列的大小时，我们可能希望给轨迹一个最小尺寸，但也要确保它们能扩展以适应添加的任何内容。例如，我可能希望我的行永远不会缩小到 100 像素以下，但如果我的内容高度扩展到 300 像素，那么我希望行也能扩展到这个高度。

网格布局提供了 `minmax()` 函数来解决这个问题。在下一个示例中，我在 `grid-auto-rows` 的值中使用了 `minmax()`。这意味着自动创建的行高度最小为 100 像素，最大为 `auto`。使用 `auto` 表示大小将取决于内容的大小，并将拉伸以在该行中为单元格中最高的项目留出空间。

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(100px, auto);
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div>一</div>
  <div>
    二
    <p>这里有更多内容。</p>
    <p>使得这里高于 100 像素。</p>
  </div>
  <div>三</div>
  <div>四</div>
  <div>五</div>
</div>
```

网格线
---

应该注意的是，当我们定义网格时，我们定义的是网格轨道，而不是网格线。网格布局会为我们创建编号的网格线来让我们来定位每一个网格元素。例如下面这个三列两行的网格中，就拥有四条纵向的网格线。

![显示编号网格线的示意图。](/zh-CN/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout/1_diagram_numbered_grid_lines.png)

网格线的编号顺序取决于文章的书写模式。在从左至右书写的语言中，编号为 1 的网格线位于最左边。在从右至左书写的语言中，编号为 1 的网格线位于最右边。网格线也可以被命名，我们将在稍后的教程中看到如何完成这一操作。

### 跨轨道放置网格项目

我们将在以后的文章中详细探讨基于行的放置。下面的示例以简单的方式演示了这一点。放置项目时，我们的目标是网格线而不是网格轨道。

在下面的示例中，我使用 `grid-column-start` (en-US)、`grid-column-end` (en-US)、`grid-row-start` (en-US) 和 `grid-row-end` (en-US) 属性，将前两个项目放置在三列轨道网格上。从左到右，第一个项目放置在第 1 列，并跨越到第 4 列，在我们的示例中，第 4 列是网格的最右边一行。它开始于第 1 行，结束于第 3 行，因此跨越了两条行轨。

第二个项目从网格列第 1 行开始，跨越一个轨道。这是默认设置，因此我不需要指定终止行。它还跨越了从第 3 行到第 5 行的两条行轨道。其他项目将放置在网格的空白处。

```html
<div class="wrapper">
  <div class="box1">一</div>
  <div class="box2">二</div>
  <div class="box3">三</div>
  <div class="box4">四</div>
  <div class="box5">五</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}

.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
}

.box2 {
  grid-column-start: 1;
  grid-row-start: 3;
  grid-row-end: 5;
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

**备注：** 别忘了你可以使用 Firefox 开发者工具中的网格检查器查看这些元素是如何被摆放在网格中的。

### 网格线定位简写

对于列，可以使用 `grid-column` 将上面使用的完整值压缩到一行，对于行，可以使用 `grid-row` 将其压缩到一行。下面的示例将提供与前面代码相同的定位，但 CSS 内容要少得多。斜线字符（`/`）前面的值为起始网格线，斜线字符（`/`）后面的值为终止网格线。

如果网格项只跨越了一个轨道，可以省略终止值。

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}

.box1 {
  grid-column: 1 / 4;
  grid-row: 1 / 3;
}

.box2 {
  grid-column: 1;
  grid-row: 3 / 5;
}
```

网格单元
----

*网格单元*（grid cell）是网格项中最小的单位，从概念上来讲其实它和表格的一个单元格很像。现在再看回我们前面的一个例子，一旦一个网格元素被定义在一个父级元素当中，那么它的子级元素将会排列在每个事先定义好的网格单元中。在下面的图中，我会将第一个网格单元作高亮处理。

![网格的第一个单元格突出显示](/zh-CN/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout/1_grid_cell.png)

网格区域
----

项目可以按行或列跨越一个或多个单元格，这样就形成了一个*网格区域*（grid area）。网格区域必须是矩形的（例如不能创建 L 形区域）。突出显示的网格区域跨越了两条行轨道和两条列轨道。

![一个网格区域](/zh-CN/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout/1_grid_area.png)

网格间距
----

网格单元格之间的*横向间距*（gutter）或*纵向间距*（alley）可以使用 `column-gap` 和 `row-gap` 属性或简写 `gap` 来创建。在下面的示例中，我在列与列之间创建了 10 像素的间隙，在行与行之间创建了 1em 的间隙。

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  column-gap: 10px;
  row-gap: 1em;
}
```

**备注：** 当网格布局首次在浏览器中使用时，`column-gap`、`row-gap` 和 `gap` 都带有 `grid-` 前缀，分别称为 `grid-column-gap`、`grid-row-gap` 和 `grid-gap`。现在，所有浏览器都支持无前缀值，但前缀版本将作为别名保留，以便安全使用。

```html
<div class="wrapper">
  <div>一</div>
  <div>二</div>
  <div>三</div>
  <div>四</div>
  <div>五</div>
</div>
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  column-gap: 10px;
  row-gap: 1em;
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

网格间距使用的任何空间都会在分配给灵活长度的 `fr` 轨道之前计算在内，而且网格间距的大小与常规网格轨道相同，但不能在间距中放置任何东西。就基于行的定位而言，网格间距就像一条粗线。

嵌套网格
----

网格项可以也成为一个网格容器。在下面的示例中，我使用了之前创建的三栏网格，并放置了两个项目。在本例中，第一个项目有一些子项目。由于这些项目不是网格的直接子项，它们不参与网格布局，因此显示在正常的文档流中。

![文档流中的嵌套网格](/zh-CN/docs/Web/CSS/CSS_grid_layout/Basic_concepts_of_grid_layout/1_nested_grids_in_flow.png)

### 不使用子网格的嵌套

如果我将 `box1` 设置为 `display: grid`，我就可以给它一个轨道定义，它也会变成一个网格项。然后，项目就会排列在这个新网格上。

```css
.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
```

```
<div class="wrapper">
  <div class="box box1">
    <div class="nested">a</div>
    <div class="nested">b</div>
    <div class="nested">c</div>
  </div>
  <div class="box box2">二</div>
  <div class="box box3">三</div>
  <div class="box box4">四</div>
  <div class="box box5">五</div>
</div>
```

```css
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  gap: 3px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

.box {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}

.box1 {
  grid-column: 1 / 4;
}

.nested {
  border: 2px solid #ffec99;
  border-radius: 5px;
  background-color: #fff9db;
  padding: 1em;
}
```

在这种情况下，嵌套网格与父网格没有任何关系。正如你在示例中看到的，它没有继承父网格的 `gap`，嵌套网格中的行也没有与父网格中的行对齐。

### 子网格

除了常规网格外，*子网格*（subgrid）还能让我们创建嵌套网格，使用父网格的轨道定义。

要使用它们，我们可以编辑上述嵌套网格示例，将 `grid-template-columns: repeat(3,1fr)` 的轨道定义更改为 `grid-template-columns: subgrid`。嵌套网格就会沿用父网格轨道来布局项目。

```css
.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
  display: grid;
  grid-template-columns: subgrid;
}
```

使用 z-index 控制层级
---------------

网格项可以占据同一单元格，在这种情况下，我们可以使用 `z-index` 属性来控制重叠项的堆叠顺序。

### 不使用 z-index 的重叠

如果我们回到按行号定位项目的示例，就可以改变这种方法，使两个项目重叠。

```html
<div class="wrapper">
  <div class="box box1">一</div>
  <div class="box box2">二</div>
  <div class="box box3">三</div>
  <div class="box box4">四</div>
  <div class="box box5">五</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}

.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
}

.box2 {
  grid-column-start: 1;
  grid-row-start: 2;
  grid-row-end: 4;
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.box {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

网格项目 `box2` 现在覆盖于 `box1` 之上，因为它在源文件顺序中排在后面。

### 控制顺序

我们可以在网格项目发生重叠时使用 `z-index` 属性控制重叠的顺序——就像放置网格项目一样。如果我们给 `box2` 设定一个低于 `box1` 的 `z-index` 值的话，`box2` 将会显示在 `box1` 的下方。

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}

.box1 {
  grid-column-start: 1;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
  z-index: 2;
}

.box2 {
  grid-column-start: 1;
  grid-row-start: 2;
  grid-row-end: 4;
  z-index: 1;
}
```

```
<div class="wrapper">
  <div class="box box1">一</div>
  <div class="box box2">二</div>
  <div class="box box3">三</div>
  <div class="box box4">四</div>
  <div class="box box5">五</div>
</div>
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.box {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

下一步
---

在本文中，我们快速了解了网格布局的各种可能性。探索并玩转代码示例，然后进入本指南的下一部分，在这里我们将真正开始挖掘 CSS 网格布局的细节。


使用命名线布局 - CSS：层叠样式表

使用命名线布局
=======

在前几篇文章中，我们已经学习了根据网格轨道创建出的网格线来定位，以及根据命名的模块区域来定位，在本文中我们将探讨如何通过为网格线命名来把这两种方法结合起来。命名网格线不可思议地有用，但是它那把名字和轨道尺寸混在一起的语法看上去令人困惑，不过通过学习本文的示例，它们会变得清晰而简单。

在定义网格时命名网格线
-----------

在用 `grid-template-rows` 和 `grid-template-columns` 属性定义网格时，可以为网格中的部分或全部网格线命名。为了便于演示，下面将使用在基于网格线定位一文中使用过的简单布局。这次我们会用命名线来创建网格。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

在定义网格时，把网格线的名字写在方括号内，名字随意。我们先为容器的起点和终点命名，既包括行的，也包括列的。接下来再把处于网格中间的块的起点和终点命名为 `columns-start` 和 `columns-end`，也是包括行和列的。不一定要把全部网格线都命名，只需要为布局时用到的关键线命名即可。

```css
.wrapper {
  display: grid;
  grid-template-columns: [main-start] 1fr [content-start] 1fr [content-end] 1fr [main-end];
  grid-template-rows: [main-start] 100px [content-start] 100px [content-end] 100px [main-end];
}
```

一旦这些网格线有了名字，我们就可以用比线序号更易用的线名字来定位项目了。

```css
.box1 {
  grid-column-start: main-start;
  grid-row-start: main-start;
  grid-row-end: main-end;
}
.box2 {
  grid-column-start: content-end;
  grid-row-start: main-start;
  grid-row-end: content-end;
}
.box3 {
  grid-column-start: content-start;
  grid-row-start: main-start;
}
.box4 {
  grid-column-start: content-start;
  grid-column-end: main-end;
  grid-row-start: content-end;
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

基于网格线布局的其他知识仍然照常可用，而且可以把命名线和线序号混合使用。为线命名的方法对于创建响应式页面特别有用，当需要在媒体查询中重新定义网格时，你就不需要通过修改线序号来改变布局，只要直接使用定义过的线名字就可以了，因为（即使在不同的布局中）线的名字总是相同的。

### 为网格线定义多个名字

你可能想要给一条线命名多个名字，比如在上例中的 sidebar-end 和 main-start 其实是同一条线。为了实现这个效果，只要把多个名字都写到方括号里，然后用空格分隔就行了：`[sidebar-end main-start]`。在引用时可以使用其中的任何一个名字。

由命名线定义的隐式网格区域
-------------

前面提到过，可以为网格线取任意名字，名字是 custom ident 类型的，它由开发者定义。不过在命名时要避免使用可能会出现在规范中的容易引起混淆的词，比如 `span`。名字两端不用加引号。

在选择名字时，如果把一个区域周围的线都用 `-start` 和 `-end` 作为后缀，就像上面的例子那样，网格就会为区域创建一个名字，名字就是后缀前的单词。再看上面的例子，我们把一些行和列命名为 `content-start` 和 `content-end`，这意味着得到了一个命名为 content 的网格区域，并且可以在这个区域中放入你想放的内容。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

下面的示例代码中，使用与上例相同的网格定义，但这次会在命名为 `content` 的区域里放入一个单独的项目。

```css
.wrapper {
  display: grid;
  grid-template-columns: [main-start] 1fr [content-start] 1fr [content-end] 1fr [main-end];
  grid-template-rows: [main-start] 100px [content-start] 100px [content-end] 100px [main-end];
}
.thing {
  grid-area: content;
}
```

```html
<div class="wrapper">
  <div class="thing">I am placed in an area named content.</div>
</div>
```

不需要通过 `grid-template-areas` 来指定区域的位置，因为它已经被命名线约束好了。

由网格区域隐式定义的命名线
-------------

上面我们看到了如何通过命名网格线来创建命名的区域，而且这个方法反过来也可行，先用命名的模块区域来定义命名线，再用命名线定位项目。下面尝试利用《网格模板区域》一文中的布局示例，来探讨由网格区域创建的命名线是如何工作的。

在这个例子中额外增加了一个 div，它的样式类名为 `overlay`。我们先用 `grid-area` 属性创建命名的区域，然后用 `grid-template-areas` 创建布局。区域的名字是：

* `hd`
* `ft`
* `main`
* `sd`

由此，即隐式地创建了行列网格线：

* `hd-start`
* `hd-end`
* `sd-start`
* `sd-end`
* `main-start`
* `main-end`
* `ft-start`
* `ft-end`

下图中可以看到被命名的网格线，注意，有些线有 2 个名字，比如 `sd-end` 和 `main-start` 指的是同一条线。

![An image showing the implicit line names created by our grid areas.](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grid_layout_using_named_grid_lines/5_multiple_lines_from_areas.png)

接下来使用隐式命名的网格线来定位项目 `overlay`，这和先显式命名网格线然后再定位是一样的。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-auto-rows: minmax(100px, auto);
  grid-template-areas:
    "hd hd hd hd hd hd hd hd hd"
    "sd sd sd main main main main main main"
    "ft ft ft ft ft ft ft ft ft";
}
.header {
  grid-area: hd;
}
.footer {
  grid-area: ft;
}
.content {
  grid-area: main;
}
.sidebar {
  grid-area: sd;
}
.wrapper > div.overlay {
  z-index: 10;
  grid-column: main-start / main-end;
  grid-row: hd-start / ft-end;
  border: 4px solid rgb(92, 148, 13);
  background-color: rgba(92, 148, 13, 0.4);
  color: rgb(92, 148, 13);
  font-size: 150%;
}
```

```html
<div class="wrapper">
  <div class="header">Header</div>
  <div class="sidebar">Sidebar</div>
  <div class="content">Content</div>
  <div class="footer">Footer</div>
  <div class="overlay">Overlay</div>
</div>
```

为了获得由命名的区域隐式创建命名线的能力，和由命名线隐式创建区域的能力，在创建网格布局时花一点时间来设计命名策略是非常值得的。慎重地选择名字对你和你的团队的意义在于，你创建网格的工作会变得容易，对其他使用和维护网格的人也大有益处。

用 repeat() 定义相同名字的多条线
---------------------

如果要给网格中所有的线都定义唯一的名字，就要用普通写法，即在定义轨道时把名字写在方括号里，而不能使用 repeat 语法。使用 repeat 语法的结果是得到有相同名字的多条线，不过这也是有用的。

### 使用 repeat() 定义 12 列的网格

下面的例子创建了一个有 12 个等宽列的网格，在定义列轨道尺寸为 1fr 之前，也定义了网格线名字 `[col-start]`，也就是说最终会创建一个 12 列的网格，每个 `1fr` 宽的列左侧的线都被命名为 `col-start`。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(12, [col-start] 1fr);
}
```

网格创建好之后，就可以在其中定位项目了。我们有多条名为 `col-start` 的线，如果有一个项目位于 `col-start` 之后，就是指命名为 `col-start` 的第一条线，也就是指最左边那条线。如果要引用其他的同名线，就要加上序号。比如要定位项目从名为 col-start 的第 1 条线开始，到第 5 条线结束，应该这样写：

```css
.item1 {
  grid-column: col-start / col-start 5;
}
```

此处也可以使用 `span` 关键字。比如下一个项目的位置从名为 `col-start` 的第 7 条线开始，跨越 3 条线。

```css
.item2 {
  grid-column: col-start 7 / span 3;
}
```

```html
<div class="wrapper">
  <div class="item1">I am placed from col-start line 1 to col-start 5</div>
  <div class="item2">I am placed from col-start line 7 spanning 3 lines</div>
</div>
```

如果在 Firefox Grid Highlighter 中查看布局，就能观察到纵向的列线，以及项目是如何依赖这些线来定位的。

![The 12 column grid with items placed. The Grid Highlighter shows the position of the lines.](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grid_layout_using_named_grid_lines/5_named_lines1.png)

### 使用轨道列表定义命名网格线

repeat 语法不仅可用于重复的单一轨道尺寸，也可以用于轨道列表。下面的代码创建了一个 8 个轨道的网格，在一个名为 `col1-start` 的 `1fr` 窄轨道之后，跟着是一个名为 `col2-start` 的 `3fr` 宽轨道。

```css
.wrapper {
  grid-template-columns: repeat(4, [col1-start] 1fr [col2-start] 3fr);
}
```

如果 repeat 语法包含相邻的两条网格线，那它们会被合并，结果就像是不用 repeat 语法的创建的，所有的网格线都有多个名字。在下面的定义中，创建了四条 `1fr` 的轨道，每条轨道都有开始名和结束名。

```css
.wrapper {
  grid-template-columns: repeat(4, [col-start] 1fr [col-end]);
}
```

如果不用 repeat 语法来定义它们，应该写成这样。

```css
.wrapper {
  grid-template-columns: [col-start] 1fr [col-end col-start] 1fr [col-end col-start] 1fr [col-end col-start] 1fr [col-end];
}
```

如果已经定义了一个轨道列表，接下来在使用 span 关键字定位项目时，不仅可以在 span 后面写一个行序数，还可以在 `span` 后面写一个命名线的行序数。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(6, [col1-start] 1fr [col2-start] 3fr);
}
.item1 {
  grid-column: col1-start / col2-start 2;
}
.item2 {
  grid-row: 2;
  grid-column: col1-start 2 / span 2 col1-start;
}
```

```html
<div class="wrapper">
  <div class="item1">
    I am placed from col1-start line 1 to col2-start line 2
  </div>
  <div class="item2">
    I am placed from col1-start line 2 spanning 2 lines named col1-start
  </div>
</div>
```

通过前面的三篇文章，我们发现使用网格布局时有非常多不同的方法来定位项目，这乍看起来有些过于复杂了，不过其实你不必把它们都用上。在实践中，我发现使用命名的模块区域是最直截了当的布局方法，它的可视化表示法能让你看到布局的效果，并且也容易在网格上移动项目。

### 三列布局

一个严格的多列布局已经可以工作得很好了，比如本文最后一部分用命名线做的演示，如果你考虑使用 Foundation 或 Bootstrap 这类框架，它们提供的是基于 12 列的网格系统，框架会导入代码然后进行计算以确保所有的列宽加在一起是 100%。如果使用网格布局，那么我们的“框架”只有这些代码就够了：

```css
.wrapper {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(12, [col-start] 1fr);
}
```

然后就可以使用这个框架来布局页面了。比如，创建一个三列的布局，有头部和尾部，HTML 代码如下所示。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > \* {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <header class="main-header">I am the header</header>
  <aside class="side1">I am sidebar 1</aside>
  <article class="content">I am the main article</article>
  <aside class="side2">I am sidebar 2</aside>
  <footer class="main-footer">I am the footer</footer>
</div>
```

接下来就可以在网格布局框架上定位元素了。

```css
.main-header,
.main-footer {
  grid-column: col-start / span 12;
}
.side1 {
  grid-column: col-start / span 3;
  grid-row: 2;
}
.content {
  grid-column: col-start 4 / span 6;
  grid-row: 2;
}
.side2 {
  grid-column: col-start 10 / span 3;
  grid-row: 2;
}
```

再一次，Firefox Grid Highlighter 工具帮助我们看到网格是如何定位项目的。

![The layout with the grid highlighted.](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grid_layout_using_named_grid_lines/5_named_lines2.png)

这就是我们需要的，不用做任何计算，网格在分配 1fr 的列轨道空间之前会自动把 10 像素的轨道间距删除掉。在你动手创建自己的布局的过程中，语法会变得越来越熟悉，你能找到适于自己的方法和喜欢创建的项目类型。尝试用不同的方法去创建一些通用的布局模式，你会找到最适合自己的工作方式。在下一篇文章中我们会探讨如何用网格定位元素——根本不需要使用定位属性！


CSS 网格布局和渐进增强 - CSS：层叠样式表

CSS 网格布局和渐进增强
=============

2017 年春天，我们第一次看到像网格（Grid）布局这样的核心规范几乎同时引入到各个浏览器中。现在 FireFox、Chrome、Opera、Safari 和 Edge 的公共版本都支持 CSS 网格布局，可虽然常用浏览器的支持意味着我们中的大部分人将很快看到大多数用户拥有网格布局支持，但也有一些旧的或不支持的浏览器需要应对。在本指南中，我们将介绍各种支持策略。

浏览器支持
-----

CSS 网格布局在所有现代浏览器中都没有前缀。对这些指南中详述的所有属性和值的支持可跨浏览器进行互操作。这意味着如果你在 Firefox 中编写一些网格布局代码，它应该在 Chrome 中以相同的方式工作。这不再是实验规范，你可以安全地在生产环境中使用它。

我的布局使用 CSS 网格布局安全吗？
-------------------

是的。无论使用任何前端技术，是否使用 CSS 网格布局都取决于网站访问者通常使用的浏览器。

开始在生产环境中使用网格布局
--------------

值得注意的是，你不必以要么*全部应用要么完全不应用*的方式使用网格。在你的设计中，你可以开始通过网格来简单地增强你的元素，从而取代它们的旧显示方式。由于网格与其他方法的交互方式，使用网格布局覆盖遗留方法的效果出奇地好。

### 浮动

浮动曾经用于创建多列布局。如果你在旧代码库使用了浮动布局，则不会发生冲突。网格项目会忽略浮动属性；事实上，*网格项目优先级更高*。在下面的示例中，我们有一个简单的 media 对象。如果 `float` 没有从遗留的 CSS 中删除，且容器是网格容器，也不会有问题。我们可以使用 CSS 网格中实现的对齐属性。

`float` 不会被应用，我们可以使用 CSS 盒子对齐属性 `align-self` 来使内容对齐到容器末尾：

```css
\* {
  box-sizing: border-box;
}
img {
  max-width: 100%;
  display: block;
}
.media {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  max-width: 400px;
  display: grid;
  grid-template-columns: 1fr 2fr;
  grid-template-areas: "img content";
  margin-bottom: 1em;
}
.media::after {
  content: "";
  display: block;
  clear: both;
}
.media .text {
  padding: 10px;
  align-self: end;
}

/\* 我们不能删除的旧代码 \*/
.media .image {
  float: left;
  width: 150px;
  margin-right: 20px;
}
```

```html
<div class="media">
  <div class="image">
    <img src="https://via.placeholder.com/150x150" alt="placeholder" />
  </div>
  <div class="text">
    This is a media object example. I am using floats for older browsers and
    grid for new ones.
  </div>
</div>
```

下图左侧显示了不支持的浏览器中的媒体对象，右侧显示了支持的浏览器中的媒体对象：

![使用网格覆盖浮动布局的简单示例。](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grid_layout_and_progressive_enhancement/10-float-simple-override.png)

### 使用特性查询

上面的例子非常简单，我们不需要编写对于不支持网格的浏览器来说会出现问题的代码，并且遗留代码对于支持网格的浏览器来说不是问题。然而，事情并不总是那么简单。

### 一个更复杂的例子

在下一个示例中，我们有一组浮动的卡片。为了使它们浮动（`float`），我们给卡片设置了宽度（`width`）。然后我们为元素设置了外边距（`margin`），并给容器设置了负边距，以在卡片之间创建间隙：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  max-width: 600px;
  margin: 0 auto;
}
.wrapper li {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper ul {
  overflow: hidden;
  margin: 0 -10px;
  padding: 0;
  list-style: none;
}
.wrapper li {
  float: left;
  width: calc(33.333333% - 20px);
  margin: 0 10px 20px 10px;
}
```

```html
<div class="wrapper">
  <ul>
    <li class="card">
      <h2>One</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Two</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Three</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Four</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Five</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Six</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
  </ul>
</div>
```

该示例演示了浮动布局的典型问题：如果将额外的内容添加到任何一张卡片，布局就会出现问题。

![浮动卡片布局展示了内容高度不均匀引起的问题。](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grid_layout_and_progressive_enhancement/10-floated-cards.png)

为了兼容旧浏览器，我们给元素设置了最小高度（`min-height`），并希望内容编辑器不会添加太多内容而导致弄乱布局！

接着，我们使用网格增强布局。我们可以将 `<ul>` 变成具有三列轨道的网格容器，但是，已经分配给列表元素本身的宽度仍然有效，并将使这些元素占据轨道宽度的三分之一：

![将网格应用到我们的容器后，元素的宽度变得不正确，因为它们显示为元素宽度的三分之一。](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grid_layout_and_progressive_enhancement/10-float-width-problem.png)

如果将宽度设置为 `auto`，则将阻止旧浏览器发生浮动行为。我们需要能够定义旧浏览器的宽度，并删除支持网格的浏览器的宽度。多亏了 CSS 特性查询 ，我们才能做到这一点。

### 使用特性查询的解决方案

如果你曾使用媒体查询创建响应式布局，那么*特性查询*看起来会非常熟悉。我们使用 `@supports` 规则检查 CSS 属性和值的支持，而无需检查视口宽度或浏览器或设备的某些特性。

```css
@supports (display: grid) {
  .wrapper {
    /\* 在这里为支持网格布局的浏览器做任何事情。 \*/
  }
}
```

特性查询具有出色的浏览器支持，并且所有支持更新的网格规范的浏览器也都支持特性查询。你可以使用它们来处理在增强型浮动布局中遇到的问题。

使用 `@supports` 规则来检查浏览器对 `display: grid` 的支持。然后，在这段使用 `<ul>` 的网格布局代码中，将 `<li>` 的宽度和最小宽度（`min-height`）都设置为 `auto`。我们还删除了外边距和负边距，并用 `gap` 属性来设置间隔，这意味着最后一排盒子上无需最终的边距。现在，即使其中一张卡片的内容比其他卡片多，布局也可以正常工作：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  max-width: 600px;
  margin: 0 auto;
}
.wrapper li {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper ul {
  overflow: hidden;
  margin: 0 -10px;
  padding: 0;
  list-style: none;
}
.wrapper li {
  float: left;
  width: calc(33.333333% - 20px);
  margin: 0 10px 20px 10px;
}
@supports (display: grid) {
  .wrapper ul {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    margin: 0;
  }
  .wrapper li {
    width: auto;
    min-height: auto;
    margin: 0;
  }
}
```

```html
<div class="wrapper">
  <ul>
    <li class="card">
      <h2>One</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Two</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Three</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Four</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Five</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Six</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
  </ul>
</div>
```

覆盖 `display` 其他的值
-----------------

由于使用浮动创建元素网格的问题，许多人会使用与上面所示的浮动方法不同的方法来布局一组卡片，`display: inline-block` 是其中之一。

我们可以再次使用特性查询来覆盖使用 `display: inline-block` 的布局，并且也不用覆盖所有内容。设置为 `inline-block` 的元素将成为网格元素，所以 `inline-block` 的行为不再生效。当处于 `display: inline-block` 显示模式时，我们在元素上使用了 `vertical-align` 属性，但该属性不适用于网格元素，因此一旦它成为网格元素，该属性就会被忽略：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  max-width: 600px;
  margin: 0 auto;
}

.wrapper li {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper ul {
  margin: 0 -10px;
  padding: 0;
  list-style: none;
}

.wrapper li {
  display: inline-block;
  vertical-align: top;
  width: calc(33.333333% - 20px);
  margin: 0 10px 20px 10px;
}
@supports (display: grid) {
  .wrapper ul {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    margin: 0;
  }
  .wrapper li {
    width: auto;
    margin: 0;
  }
}
```

```html
<div class="wrapper">
  <ul>
    <li class="card">
      <h2>One</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Two</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Three</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Four</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Five</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
    <li class="card">
      <h2>Six</h2>
      <p>We can use CSS Grid to overwrite older methods.</p>
    </li>
  </ul>
</div>
```

我们需要再次解决的是元素的宽度，然后是想要增强的任何其他属性。在这个例子中，我们再次使用了 `grid-gap`，而不是外边距和负边距来创建间隙。

规范如何定义这些覆盖关系？
-------------

CSS 网格布局规范详细说明了为什么当某物成为网格元素时我们可以覆盖某些属性的行为。该规范的关键部分是：

* Establishing Grid Containers
* Grid Items
* Grid Item Display

由于规范中对此行为进行了详细说明，因此你可以放心地在对旧版浏览器的支持中使用这些覆盖方法。这里描述的任何内容都不应被视为“hack”。相反，我们正在利用网格规范来详细说明不同布局方法之间的交互方式。

### `display` 的其他值

如 CSS display 规范中所定义，当一个元素的父元素设置为 `display: grid` 时，它会被块化。这就是为什么当我们的元素被设置为 `inline-block` 时，`display: inline-block` 不再生效的原因。

如果你使用 `display: table` 作为旧版布局，则设置为 `display: table-cell` 的元素会生成匿名盒子。因此，如果你在没有任何父元素设置为 `display-table` 的情况下使用 `display: table-cell`，则会在任何相邻单元格周围创建匿名表格包装器，就像将它们包裹在 div 或其他设置为 `display: table` 的元素中一样。如果你将一个元素设置为 `display: table-cell` ，然后在特性查询中将父级更改为 `display: grid` ，则不会创建匿名盒子。这意味着你可以覆盖基于 `display: table` 的布局，且无需额外的匿名盒子。

### 浮动元素

正如我们已经看到的，`float` 和 `clear` 对网格元素没有影响。因此，无需显式地将元素设置为 `float: none`。

### 垂直对齐

对齐属性 `vertical-align` 对网格元素没有影响。在使用 `display: inline-block` 或 `display: table` 的布局中，你可以使用 vertical-align 属性来执行基本对齐。在网格布局中，则拥有更强大的对齐属性。

### 多列布局

你还可以使用多列布局来支持旧版浏览器，因为在应用于网格容器时，`column-*` 属性不会被应用。

参见
--

* 有关特性查询以及如何恰当地使用它们，请参阅在 CSS 中使用特性查询（2016）。
* CSS Grid and the New Autoprefixer


CSS 网格，逻辑值和书写模式 - CSS：层叠样式表

CSS 网格，逻辑值和书写模式
===============

在前面的文章中，我们已经接触了网格布局的一个重要特性：被纳入规范的对不同书写模式的支持。本文我们将探讨在网格和其他现代布局方式下的这个特性的表现，以及学习一些关于书写模式和逻辑属性与物理属性的知识。

逻辑属性与物理属性及逻辑值与物理值
-----------------

CSS 中布满了**物理**位置的关键字——left 和 right，top 和 bottom。当使用绝对位置来定位项目时，就要使项目围绕上用物理关键字描述的偏移量。在下面的代码片断中，项目被定位到距容器顶部 20 像素，并且距容器左侧 30 像素：

```css
.container {
  position: relative;
}
.item {
  position: absolute;
  top: 20px;
  left: 30px;
}
```

```html
<div class="container">
  <div class="item">Item</div>
</div>
```

另一个用到物理关键字的地方是使用 `text-align: right` 把文本对齐到右侧，这也是 CSS 中的**物理**属性。当我们为项目增加外边距、内边距和边框时会使用像 `margin-left`，`padding-left` 这样的物理属性。

把这些关键字称为*物理*属性，是因为它们与你看到的屏幕紧密相关，左永远是左，不管文本流动的方向如何。

在开发有多种语言的网站时，如果其中包含了从右侧而不是从左侧开始书写的文字，物理属性就会成为一个问题。浏览器很擅长处理文本方向，不需要真的在一种 rtl （从右到左）的语言下开发，我们也可以一窥究竟。下面的例子里有两个段落，一个段落没有设置 `text-align` 属性，另一个段落的 `text-align` 设置为 `left`。在 `html` 元素上添加 `dir="rtl"` 声明，就会把书写模式从默认的 `ltr` （从左到右）的英语切换为 `rtl` （从右到左）的语言。我们可以看到，第一段仍然是从左到右显示，因为 `text-align` 的值为 `left`，但第二段把文字的流动方向切换成了从右到左。

![A simple example of text direction.](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grids_logical_values_and_writing_modes/8_direction_simple_example.png)

这只是在使用物理属性和值时引起问题的一个非常简单的例子，它们阻止浏览器切换书写模式，因为这些物理属性和值已经假设文字的流动方向一定是从左到右、从上到下的。

### 逻辑属性和值

逻辑属性和值不会预设文字方向，这也是为什么在网格布局中要实现对齐到容器的开始位置时使用 `start` 关键字的原因。对我来说，因为我使用英语工作，所以 `start` 就是左侧，不过它并不总是代表左侧，并不能根据 `start` 这个词推断出物理位置。

块和行内
----

如果我们用逻辑属性而不是物理属性来思考，就不能使用从左到右、从上到下的方式观察世界，我们需要一个新的参考点，也就是在此前的文章中讨论*对齐*时接触过的*块轴*与*行内轴*。理解它们是非常重要的，如果开始用块轴与行内轴的方式来看待布局，在网格布局中使用到的术语就变得非常有意义了。

![An image showing the default direction of the Block and Inline Axes.](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grids_logical_values_and_writing_modes/8-horizontal-tb.png)

CSS 书写模式
--------

现在我要介绍另一个规范：CSS 书写模式规范，并在下面的例子中给出演示。这个规范详细描述了如何在 CSS 中使用多种不同的书写模式，不仅是支持与英语不同书写模式的语言，而且提供了更富创造性的用途。我将通过使用 `writing-mode` 属性来改变网格的书写模式，演示逻辑值是如何工作的。如果你想更深入地探讨书写模式，我推荐你阅读 Jen Simmons 的优秀文章：CSS Writing Modes，这篇文章对标准的讨论比本文要深入得多。

### writing-mode

书写模式不仅可以使文字从左到右或从右到左显示，`writing-mode` 属性还可以设置其他的文字流动方向。`writing-mode` 属性有以下可选值：

* `horizontal-tb`
* `vertical-rl`
* `vertical-lr`
* `sideways-rl`
* `sideways-lr`

属性值 `horizontal-tb` 是 web 上显示文本的默认效果，也就是你现在正在阅读的这篇文章的方向，其他的属性值将会改变文字的流动方向，能匹配世界各地不同的书写模式，这些细节你都可以在 Jen 的文章中看到。下面用两个段落展示一个简单的例子，第一个段落使用默认的 `horizontal-tb`，第二个段落使用 `vertical-rl`，这种模式下文本仍然从左到右排列，不过文本的方向却是垂直的——现在行内文本是从页面的顶部到底部向下流动的。
```

.wrapper > p {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  margin: 1em;
  color: #d9480f;
  max-width: 300px;
}
```

```html
<div class="wrapper">
  <p style="writing-mode: horizontal-tb">
    I have writing mode set to the default <code>horizontal-tb</code>
  </p>
  <p style="writing-mode: vertical-rl">
    I have writing mode set to <code>vertical-rl</code>
  </p>
</div>
```

网格布局中的书写模式
----------

现在让我们来做一个网格布局的实验，就可以看到书写模式是如何改变你对块轴和行内轴的看法的。

### 默认书写模式

下面例子是一个二行三列的网格，也就是说有三个沿着块轴方向的轨道。在默认的书写模式下，网格自动定位项目的流向，是从左上开始，向右延伸，填满行内轴方向的三个格子，然后转到下一行，创建一个新的行轨道，继续定位更多的项目：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(2, 100px);
  grid-gap: 10px;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
  <div class="item5">Item 5</div>
</div>
```

### 设置书写模式

如果给网格容器加上 `writing-mode: vertical-lr` 属性，就可以看到块轴和行内轴都转到不同的方向了，块轴从左到右地穿过页面，行内轴则从上到下到流动。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  writing-mode: vertical-lr;
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(2, 100px);
  grid-gap: 10px;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
  <div class="item5">Item 5</div>
</div>
```

![A image showing the direction of Block and Inline when writing-mode is vertical-lr](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grids_logical_values_and_writing_modes/8-vertical-lr.png)

用于对齐的逻辑值
--------

因为块轴和行内轴可以改变方向，所以在对齐属性中使用的逻辑值就具有更丰富的含义。

在下面的例子中，网格被设置了 `writing-mode: vertical-lr` 属性，我们将使用对齐属性来对齐项目。`start` 和 `end` 属性值仍然像在默认的书写模式下那样保留着它们的逻辑，但却已经不是 left 和 right，top 和 bottom 所能够表示的了。只要我们把网格翻转到一边，就会发生这种情况：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  writing-mode: vertical-lr;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
  grid-gap: 10px;
}

.item1 {
  grid-column: 1 / 4;
  align-self: start;
}

.item2 {
  grid-column: 1 / 3;
  grid-row: 2 / 4;
  align-self: start;
}

.item3 {
  grid-column: 3;
  grid-row: 2 / 4;
  align-self: end;
  justify-self: end;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
</div>
```

如果你要看看在先上到下再从右到左的书写模式，把 `vertical-lr` 换成 `vertical-rl`，就能得到一个从右到左的垂直书写模式。

自动定位和书写模式
---------

如上例所示，我们已经看到当书写模式改变了方向时网格是如何定位项目的，项目将被沿着行内轴排列直到下一行，只是行内轴不再总是沿着从左到右的方向罢了。

基于网格线的定位和书写模式
-------------

要切记，当用网格线序号来定位项目时，不管在哪种书写模式下，第 1 行永远代表开始的那条网格线，第 -1 行永远代表结束的那条网格线。

### 从左到右文本的基于网格线的定位

在下面的例子中，网格的默认方向是 `ltr`（从左到右），用基于网格线定位方式定位了三个项目。

* Item 1 从列的第 1 条线开始，跨越 1 个轨道。
* Item 2 从列表的第 -1 条线开始，跨越到第 -3 条线。
* Item 3 从列的第 1 条线开始，跨越到列的第 3 条线。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, 100px);
  grid-gap: 10px;
}
.item1 {
  grid-column: 1;
}
.item2 {
  grid-column: -1 / -3;
}
.item3 {
  grid-column: 1 / 3;
  grid-row: 2;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
</div>
```

### 从右到左文本的基于网格线的定位

如果现在为网格容器增加一个 `direction` 属性，属性值为 `rtl`，那么 第 1 条线就变到了网格的右侧，而第 -1 条线则变到左侧。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  direction: rtl;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, 100px);
  grid-gap: 10px;
}
.item1 {
  grid-column: 1;
}
.item2 {
  grid-column: -1 / -3;
}
.item3 {
  grid-column: 1 / 3;
  grid-row: 2;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
</div>
```

这表明，如果要切换页面整体或部分的文本方向，并且正在使用网格线，那么如果不想让布局受到影响，应该命名网格线。有些情况下，比如网格包含文本内容，切换后的结果可能正是你想要的，但对于其他情况却不一定。

### `grid-area` 属性值的奇怪顺序

可以把定义网格区域的四条线合并为一个值传给 `grid-area` 属性，在第一次使用这个属性时，人们经常会惊讶它的写法没有遵从 `margin` 的按顺时针的简写顺序：top，right，bottom，left。

但是 `grid-area` 的简写顺序却是：

* `grid-row-start`
* `grid-column-start`
* `grid-row-end`
* `grid-column-end`

对于英语书写模式来说，从左到右的顺序应该是：

* `top`
* `left`
* `bottom`
* `right`

`grid-area` 的简写顺序是逆时针！与我们常用的 `margin` 和 `padding` 相反。你要意识到 `grid-area` 是从“块和行内”的角度看世界的，牢记应该先设置两条开始线，再设置两条结束线。这样的顺序才更符合逻辑！

书写模式与网格布局的结合
------------

书写模式除了为特定语言处理提供便利，另外对于文档的显示效果，也可以提供 `ltr` （从左到右）模式之外的创新性。在下面的例子中，想在网格布局的一侧展示若干链接，就可以通过变更书写模式把这些链接按列轨道方向排列：

```css
.wrapper {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: 1fr auto;
  font:
    1em Helvetica,
    Arial,
    sans-serif;
}
.wrapper nav {
  writing-mode: vertical-lr;
}
.wrapper ul {
  list-style: none;
  margin: 0;
  padding: 1em;
  display: flex;
  justify-content: space-between;
}
.wrapper a {
  text-decoration: none;
}
```

```html
<div class="wrapper">
  <div class="content">
    <p>
      Turnip greens yarrow ricebean rutabaga endive cauliflower sea lettuce
      kohlrabi amaranth water spinach avocado daikon napa cabbage asparagus
      winter purslane kale. Celery potato scallion desert raisin horseradish
      spinach carrot soko. Lotus root water spinach fennel kombu maize bamboo
      shoot green bean swiss chard seakale pumpkin onion chickpea gram corn pea.
      Brussels sprout coriander water chestnut gourd swiss chard wakame kohlrabi
      beetroot carrot watercress. Corn amaranth salsify bunya nuts nori azuki
      bean chickweed potato bell pepper artichoke.
    </p>

    <p>
      Nori grape silver beet broccoli kombu beet greens fava bean potato
      quandong celery. Bunya nuts black-eyed pea prairie turnip leek lentil
      turnip greens parsnip. Sea lettuce lettuce water chestnut eggplant winter
      purslane fennel azuki bean earthnut pea sierra leone bologi leek soko
      chicory celtuce parsley jícama salsify.
    </p>
  </div>
  <nav>
    <ul>
      <li><a href="">Link 1</a></li>
      <li><a href="">Link 2</a></li>
      <li><a href="">Link 3</a></li>
    </ul>
  </nav>
</div>
```

物理值和网格布局
--------

在构建网站时经常会遇到物理属性，尽管网格定位和对齐属性及它们的值都遵从书写模式，还是有很多时候即使在网格中也不得不使用物理属性和值。在 网格布局中的盒模型对齐 一文中，演示了在网格区域中如何利用自动边距，而自动边距也是 flexbox 布局的一种技巧，尽管这样又把布局和物理空间纠结到了一起。

如果在网格区域中使用绝对定位，那么你就会使用物理偏移量调整网格区域中的项目的位置。关键是要掌握使用物理属性与逻辑属性的力度，举例来说，要衡量把 `ltr` 切换到 `rtl` 时你需要对 CSS 做多少修改。

### 逻辑属性无处不在！

新的布局方法赋予使用逻辑值定位项目的能力，不过如果和使用物理属性的 `margin`、`padding` 属性混用，切记这些物理属性并不会依据书写模式来改变它们的显示效果。

CSS 逻辑属性规范的目标是改变现状，在未来的 CSS 中，`margin-left` 和 `margin-right` 将与逻辑属性相同。Firefox 已经实现了，所以你现在就可以在 Firefox 中试上一试。未来如果得到全面支持，那么通过网格学习到的“块和行内”的知识，你也能马上举一反三地用在其他地方了。


网格布局中的盒模型对齐 - CSS：层叠样式表

网格布局中的盒模型对齐
===========

CSS 网格布局实现了盒模型对齐 Level 3 规范，与用于弹性容器中元素对齐的弹性盒的标准相同。这个规范详细约定了在不同的布局方式下如何处理对齐问题。布局方法会尽可能地符合规范，但仍因特性与约束的不同而存在行为的差异，浏览器还未完全实现所有的规范；好在 CSS 网格布局已被广泛支持。

本文将演示它是如何工作的，你会发现很多属性和值与弹性盒布局中的用法是类似的，由于网格布局是二维的，弹性盒布局是一维的，所以你也会发现它们有一些小区别。我们就从处理网格对齐时用到的两条轴线开始吧。

网格布局的两条轴线
---------

网格布局方式下共有两条轴线用于对齐——*块轴*和*行轴*（内联轴）。块方向的轴是采用块布局时块的排列方向。假设页面中有两个段落，其中一个显示在另一个下面，所以这个方向的轴被称为块轴。

![块轴是垂直方向的。](/zh-CN/docs/Web/CSS/CSS_grid_layout/Box_alignment_in_grid_layout/block_axis.png)

*行轴*与块方向的轴垂直，它的方向和常规内联流中的文本方向一致。

![内联/行轴是水平方向的。](/zh-CN/docs/Web/CSS/CSS_grid_layout/Box_alignment_in_grid_layout/7_inline_axis.png)

我们可以把网格区域中的内容，以及网格轨道整体与这两条轴线对齐。

对齐元素到块轴
-------

属性 `align-self` 和 `align-items` 用于控制元素在块方向的轴上对齐，通过设置这两个属性，可以改变网格区域中的元素的对齐方式。

### 使用 align-items

在下面的示例中，网格中包含四个网格区域，可以通过网格容器上的 `align-items` 属性，把元素的对齐方式设置为下列值之一：

* `auto`
* `normal`
* `start`
* `end`
* `center`
* `stretch`
* `baseline`
* `first baseline`
* `last baseline`
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 10px;
  grid-auto-rows: 100px;
  grid-template-areas:
    "a a a a b b b b"
    "a a a a b b b b"
    "c c c c d d d d"
    "c c c c d d d d";
  align-items: start;
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>
```

注意，一旦设置了 `align-items: start`，每个子元素——`<div>` 的高度将由 `<div>` 中的内容决定。这与省略 `align-items`（会将每个 `<div>` 的高度会被拉伸到网格区域的高度）完全相反。

设置了 `align-items` 属性，就相当于为网格的所有子元素都设置了 `align-self` 属性，当然也可以为单独的某一个网格元素设置它的个性化的 `align-self` 属性。

### 使用 align-self

下一个示例演示了将 `align-self` 设置为不同的值的对齐效果。第一个区域的 `align-self` 采用默认值即 `stretch`，第二个元素的 `align-self` 的值为 `start`，第三个元素的值为 `end`，第四个元素的值为 `center`。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 10px;
  grid-auto-rows: 100px;
  grid-template-areas:
    "a a a a b b b b"
    "a a a a b b b b"
    "c c c c d d d d"
    "c c c c d d d d";
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
  align-self: start;
}
.item3 {
  grid-area: c;
  align-self: end;
}
.item4 {
  grid-area: d;
  align-self: center;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>
```

### 具有固定宽高比的元素

规范中对 `align-self` 的默认行为是拉伸（`stretch`），例外的情况是若元素具有固定宽高比，行为就改为与轴起点对齐（`start`）。此项例外的原因在于，如果把一个有固定宽高比的元素拉伸，将导致它扭曲变形。

虽然规范中已经阐明如何处理，但部分浏览器目前还没有按规范正确地实现，在此特性尚未被完全支持时，为了确保网格中的元素比如图片不被拉伸，可以通过把 `align-self` 和 `justify-self` 都设置为 `start` 来模拟正确的实现效果。

对齐元素到行轴
-------

与 `align-items` 和 `align-self` 用于对齐元素到块轴类似，`justify-items` 和 `justify-self` 用于对齐元素到行轴，可选值也和 `align-self` 一样。

* `auto`
* `normal`
* `start`
* `end`
* `center`
* `stretch`
* `baseline`
* `first baseline`
* `last baseline`

借用上面演示过的设置 `align-items` 的示例，下面把它改为设置 `justify-self` 属性。

默认的对齐方式仍然是 `stretch`，除非元素具有固定宽高比。也就是说在默认情况下，网格元素会覆盖网格区域，除非改变它们的对齐方式。下面的例子中，第一个元素演示了默认的对齐效果：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 10px;
  grid-auto-rows: 100px;
  grid-template-areas:
    "a a a a b b b b"
    "a a a a b b b b"
    "c c c c d d d d"
    "c c c c d d d d";
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
  justify-self: start;
}
.item3 {
  grid-area: c;
  justify-self: end;
}
.item4 {
  grid-area: d;
  justify-self: center;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>
```

与 `align-self` 和 `align-items` 的关系类似，通过为网格容器设置 `justify-items` 属性，就相当于为所有的元素都设置了 `justify-self` 属性。

属性 `justify-self` 和 `justify-items` 在弹性盒布局中未被实现，这是因为弹性盒布局本质上是一维的，在轴上会有多个元素，无法单独对齐其中某一个元素。要在弹性盒布局中实现沿主轴（即行轴）上对齐元素，可以使用 `justify-content` 属性。

### 简写属性

`place-items` 属性是对 `align-items` 和 `justify-items` 的简写。

`place-self` (en-US) 属性是对 `align-self` 和 `justify-self` 的简写。

使元素居于区域正中
---------

通过组合使用 align 和 justify 属性，让元素居于网格区域的正中就变得非常容易了。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  grid-auto-rows: 200px;
  grid-template-areas:
    ". a a ."
    ". a a .";
}
.item1 {
  grid-area: a;
  align-self: center;
  justify-self: center;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
</div>
```

对齐网格轨道到块轴
---------

设想这样一种场景，网格轨道整体占据的空间小于网格容器，那么就可以在容器中对齐网格轨道。针对块轴和行轴，分别使用 `align-content` 对齐到块轴，使用 `justify-content` 对齐到行轴。`place-content` 属性则是对 `align-content` 和 `justify-content` 的简写。属性 `align-content`、`justify-content` 和 `place-content` 的可选值都是：

* `normal`
* `start`
* `end`
* `center`
* `stretch`
* `space-around`
* `space-between`
* `space-evenly`
* `baseline`
* `first baseline`
* `last baseline`

下面的示例中，网格容器的宽高都是 500 像素，分别定义了行轨道和列轨道各 3 条，轨道尺寸为 100 像素，轨道间隙为 10 像素。可知，网格容器的块方向和文字方向都留有多余的空间。

属性 `align-content` 要设置在网格容器上，因为它的效果应用在整个网格中。

### 默认对齐方式

网格布局中默认的行为是对齐到起点（`start`），所以我们看到网格轨道整体居于网格的左上角，紧挨着起始的网格线：

```css
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>
```

### 设置 align-content: end

如果把容器中 `align-content` 的值改为 `end`，那么网格轨道整体都会移到贴近块方向轴线的最后一条线：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
  align-content: end;
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>
```

### 设置 align-content: space-between

也可以为这个属性设置与弹性盒布局方式类似的用于分配空间的值：`space-between`，`space-around` 和 `space-evenly`。比如把 `align-content` 的值改为 `space-between`，观察网格元素在空间中是如何摆放的：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
  align-content: space-between;
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>
```

有必要强调一下，这些与分配空间有关的值会使网格元素变大。如果元素跨越了多于一条轨道，因为轨道的间隙变大了，所以元素也变得更大了。因为精确尺寸的网格较为常用，所以如果你决定使用这些值，一定要确保其中的内容能够适应多出来的空间，或者在使用这些属性值时，把元素的对齐方式设置为对齐到起点（`start`），可能会比设置为拉伸（`stretch`）要好。

下图中的网格使用了 `align-content` 属性，左侧的值为 `start`，右侧的值为 `space-between`。观察 item 1 和 item 2，它们都跨越了两条行轨道，右侧的图因为增加了轨道间隙，所以它们占据的空间变大了：

![演示使用 space-between 时元素如何变大。](/zh-CN/docs/Web/CSS/CSS_grid_layout/Box_alignment_in_grid_layout/7_space-between.png)

对齐网格轨道到行轴
---------

在行轴上使用 `justify-content` 属性可以获得与在块轴上使用 `align-content` 相同的对齐效果。

继续利用上面的示例，设置 `justify-content` 的值为 `space-around`，那些占据超过一列的元素将因此获得额外的空间：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
  align-content: space-between;
  justify-content: space-around;
}
.item1 {
  grid-area: a;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>
```

对齐和自动外边距
--------

另一个在网格区域内使元素对齐的方法是使用自动外边距。如果你曾经用过把容器的左右外边距都设置为 `auto` 以让页面布局显示在视口中间的方法的话，你肯定知道自动外边距能够消化掉全部的多余空间。当把两侧的外边距都设置为 `auto` 时，块元素就会被挤到中间，多余的空间则被留到两侧。

在下面的例子中，元素 item 1 的左外边距被设置成 `auto`，可以看到内容被推到了区域右侧，因为在为元素的内容分配了空间之后，自动外边距占据了剩余的空间：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 100px);
  grid-template-rows: repeat(3, 100px);
  height: 500px;
  width: 500px;
  gap: 10px;
  grid-template-areas:
    "a a b"
    "a a b"
    "c d d";
}
.item1 {
  grid-area: a;
  margin-left: auto;
}
.item2 {
  grid-area: b;
}
.item3 {
  grid-area: c;
}
.item4 {
  grid-area: d;
}
```

```html
<div class="wrapper">
  <div class="item1">Item 1</div>
  <div class="item2">Item 2</div>
  <div class="item3">Item 3</div>
  <div class="item4">Item 4</div>
</div>
```

在 Firefox Grid Highlighter 中可以清晰地看到元素是如何被对齐的：

![使用 Grid Highlighter 展示自动外边距。](/zh-CN/docs/Web/CSS/CSS_grid_layout/Box_alignment_in_grid_layout/7_auto_margins.png)

对齐和书写模式
-------

上面所有的例子都是工作在英语这样一种从左到右的语言环境下，这意味着当从物理方向观察时，网格的起始线是在从左上开始的。

CSS 网格布局和盒模型对齐规范是为了解决 CSS 中的书写模式而设计的。这意味着，如果你用一种从右到左的语言工作，比如阿拉伯语，那网格的起始线就应该是从右上开始，此时 `justify-content: start` 也将使网格轨道从网格的右侧开始。

为 `margin-right` 和 `margin-left` 设置自动外边距，或者使用绝对位置如 `top`、`right`、`bottom` 和 `left` 来设置偏移量对书写模式来说并不是一种友好的表达方式。在下一篇文章中，我们会深入讨论 CSS 网格布局、盒模型对齐和书写模式之间的关系，理解这些原理，对于开发用多种语言显示的网站，或者设计混合了多种语言和书写模式的页面将大有益处。


CSS 网格中基于线的定位 - CSS：层叠样式表

CSS 网格中基于线的定位
=============

在探讨网格布局的基础概念一文中，我们了解了如何使用线编号来排列元素，本文则会全面探索这个基础特性如何工作。

了解编号线是最好的探索网格布局方式的起点，当你使用网格布局时，编号线总是存在。这些线从 1 开始按行和列编号。要注意的是网格是根据书写方向来编号的。在像英文这样从左至右书写的语言中，网格线的 1 是最左边的线。当使用从右至左书写的语言时，网格线 1 就是最右边的线。我们会在之后的文章中深入探讨书写模式和网格间的交互。

基础示例
----

在这个非常简单的例子中，我们使用了 3 行 3 列的导轨，从而每个方向上我们有 4 条线。

网格容器中有 4 个子元素。如果我们不定义它们的位置，它们会按照自动定位规则布局，即前 4 个单元格中各 1 个元素。你可使用 Firefox Grid Highlighter 查看网格是如何定义行和列的。

![在开发者工具中突出显示的网格](/zh-CN/docs/Web/CSS/CSS_grid_layout/Grid_layout_using_line-based_placement/3_hilighted_grid.png)
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

使用线编号定位元素
---------

我们可以使用基于线的定位控制元素在网格上的位置。比如我想要第一个元素从网格的最左开始，占 1 个列导轨。它还应该从第 1 行线开始，延伸至第 4 行线：

```css
.box1 {
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 1;
  grid-row-end: 4;
}
```

当你为某些元素定位，剩下的元素会继续按照自动定位规则定位。我们会在以后的文章中介绍这些规则，但现在你可以看到网格开始把未定位的元素放入空的单元格。

在逐个定义元素后，我们把所有 4 个元素都填充到了网格中。注意，我们可以留空一些单元格。网格布局的一个优势是：无需给元素周围加上 margin 来阻止文档流自动填补空白，就能实现设计中的留白区域。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

```css
.box1 {
  grid-column-start: 1;
  grid-column-end: 2;
  grid-row-start: 1;
  grid-row-end: 4;
}
.box2 {
  grid-column-start: 3;
  grid-column-end: 4;
  grid-row-start: 1;
  grid-row-end: 3;
}
.box3 {
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
}
.box4 {
  grid-column-start: 2;
  grid-column-end: 4;
  grid-row-start: 3;
  grid-row-end: 4;
}
```

`grid-column` 和 `grid-row` 的简写
------------------------------

我们用了不少代码定位每个元素，你应该不会惊讶有简写。`grid-column-start` (en-US) 和 `grid-column-end` (en-US) 属性可以合并为 `grid-column`、`grid-row-start` (en-US) 和 `grid-row-end` (en-US) 则合并为 `grid-row`。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

```css
.box1 {
  grid-column: 1 / 2;
  grid-row: 1 / 4;
}
.box2 {
  grid-column: 3 / 4;
  grid-row: 1 / 3;
}
.box3 {
  grid-column: 2 / 3;
  grid-row: 1 / 2;
}
.box4 {
  grid-column: 2 / 4;
  grid-row: 3 / 4;
}
```

默认跨度
----

在上例中，为了展示这些属性，我们指定了每个结束行线和列线，但实际上如果一个元素只延伸一个轨道的话，你可以省略 `grid-column-end` 或 `grid-row-end` 值。元素默认延伸一个轨道。

### 默认跨度的普通写法

我们最初的示例的普通写法会是这样：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

```css
.box1 {
  grid-column-start: 1;
  grid-row-start: 1;
  grid-row-end: 4;
}
.box2 {
  grid-column-start: 3;
  grid-row-start: 1;
  grid-row-end: 3;
}
.box3 {
  grid-column-start: 2;
  grid-row-start: 1;
}
.box4 {
  grid-column-start: 2;
  grid-column-end: 4;
  grid-row-start: 3;
}
```

### 默认跨度的简写

当省略了跨越一个轨道的元素的斜杠和第二个值，我们的简写则会是这样：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

```css
.box1 {
  grid-column: 1;
  grid-row: 1 / 4;
}
.box2 {
  grid-column: 3;
  grid-row: 1 / 3;
}
.box3 {
  grid-column: 2;
  grid-row: 1;
}
.box4 {
  grid-column: 2 / 4;
  grid-row: 3;
}
```

`grid-area` 属性
--------------

我们可以更进一步，给每个元素只定义一个属性 `grid-area`。值的顺序如下

* grid-row-start
* grid-column-start
* grid-row-end
* grid-column-end
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

```css
.box1 {
  grid-area: 1 / 1 / 4 / 2;
}
.box2 {
  grid-area: 1 / 3 / 3 / 4;
}
.box3 {
  grid-area: 1 / 2 / 2 / 3;
}
.box4 {
  grid-area: 3 / 2 / 4 / 4;
}
```

`grid-area` 的值的顺序看起来可能有点奇怪，比如说它正好和定义 margin 和 padding 的简写的值的顺序相反。但如果说是因为它与 CSS 书写模式规范中的书写方向相关就不难理解了。我们会在之后的文章中探讨网格与书写模式的关系，但我们有 4 个书写流关联的方向：

* 块起始（block-start）
* 块结束（block-end）
* 行起始（inline-start）
* 行结束（inline-end）

我们现在使用的是英语，一种从左至右书写的语言。块起始就是网格容器的顶端行线，块结束就是底端行线。行起始是左端列线，因为行起始与当前书写模式的起点一致，行结束就是网格右端列线。

当我们用 `grid-area` 属性来定义网格区域时，我们先定义块起始（`block-start`）和行起始（`inline-start`），然后再定义块结束（`block-end`）和行结束（`inline-end`）。起初，我们可能会因为习惯了顶、右、底、左的属性定义顺序，觉得这个顺序奇怪，但当从网站的书写模式有多个方向的角度思考，这就显得合理了。

反方向计数
-----

我们也可以从行和块结束线开始反方向计数，对于英语来说就是右端的列线和底端的行线。这些线会被记为 `-1`，然后你可以从这往前数，所以倒数第 2 条线会被记为 `-2`。值得注意的是最后一条线是指显式定义网格的最后一条线，即由 `grid-template-columns` 和 `grid-template-rows` 定义的网格，并不把隐式定义网格的加入的行和列纳入考虑。

下面这个示例中，我们通过从右端和底端开始定义布局，把之前的示例的布局翻转了。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

```css
.box1 {
  grid-column-start: -1;
  grid-column-end: -2;
  grid-row-start: -1;
  grid-row-end: -4;
}
.box2 {
  grid-column-start: -3;
  grid-column-end: -4;
  grid-row-start: -1;
  grid-row-end: -3;
}
.box3 {
  grid-column-start: -2;
  grid-column-end: -3;
  grid-row-start: -1;
  grid-row-end: -2;
}
.box4 {
  grid-column-start: -2;
  grid-column-end: -4;
  grid-row-start: -3;
  grid-row-end: -4;
}
```

### 使元素跨越整个网格

拥有从开始计数和从末尾计数这两种定位方法使得使一个元素跨越整个网格变得很方便：

```css
.item {
  grid-column: 1 / -1;
}
```

间距
--

CSS 网格规范加入了用 `column-gap` 和 `row-gap` 属性定义列间距和行间距的能力。这两个属性的行为和多列布局中的 `column-gap` 属性很像。

**备注：** 在浏览器首次引入网格属性 `column-gap`、`row-gap` 和 `gap` 时，具有 `grid-` 前缀。分别是 `grid-column-gap`、`grid-row-gap` 和 `grid-gap`。

浏览器正在更新它们的渲染引擎，以删除这一前缀，但是携带有前缀的版本将以别名的形式进行维护，使得它们可以被安全地使用。

间距只出现在网格轨道与轨道之间，它们并不会出现在网格容器的四周。通过在网格容器上定义这些属性，我们给上例加上了间距：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

```css
.box1 {
  grid-column: 1;
  grid-row: 1 / 4;
}
.box2 {
  grid-column: 3;
  grid-row: 1 / 3;
}
.box3 {
  grid-column: 2;
  grid-row: 1;
}
.box4 {
  grid-column: 2 / 4;
  grid-row: 3;
}
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
  column-gap: 20px;
  row-gap: 1em;
}
```

### 网格间距简写

这两个属性可以用 `gap` 简写。如果你只给出一个值，那这个值会同时应用于行间距和列间距。如果你给了两个值，第一个会被用于 `row-gap`，第二个则会被用于 `column-gap`。

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
  gap: 1em 20px;
}
```

从基于线定位的角度来说，间距的行为就像是使基线变得特别宽。所有从这条线开始的东西会从间距结束的地方开始，你并不能定位也不能放任何东西到这个间距的空间中。如果你希望得到行为和轨道行为相似的间距，你当然可以定义轨道来作为间距。

使用 `span` 关键字
-------------

除了”起始线与结束线“的定位方法，你还可以使用”起始线与跨越轨道数量“的定位方法
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 100px);
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div class="box1">One</div>
  <div class="box2">Two</div>
  <div class="box3">Three</div>
  <div class="box4">Four</div>
</div>
```

```css
.box1 {
  grid-column: 1;
  grid-row: 1 / span 3;
}
.box2 {
  grid-column: 3;
  grid-row: 1 / span 2;
}
.box3 {
  grid-column: 2;
  grid-row: 1;
}
.box4 {
  grid-column: 2 / span 2;
  grid-row: 3;
}
```

你也可以在 `grid-row-start`/`grid-row-end` 和 `grid-column-start`/`grid-column-end` 属性中使用 `span` 关键字。接下来两个例子会创建同样的网格。第一个例子中我们设定了起始行，然后说我们想结束线在跨越 3 条线之后。那这个元素就会从 1 号线开始，跨越 3 条线，到 4 号线结束。

```css
.box1 {
  grid-column-start: 1;
  grid-row-start: 1;
  grid-row-end: span 3;
}
```

第二个例子中，我们定义了结束行线，然后设置起始线为跨越 3 条线。意味着这个元素会从指定的线往上跨越 3 条线。这个元素会从 4 号线开始，跨越 3 条线到 1 号线。

```css
.box1 {
  grid-column-start: 1;
  grid-row-start: span 3;
  grid-row-end: 4;
}
```

为了熟悉基于线的定位方式，你可以尝试用网格布置几个列宽不同的元素来实现一些常见布局。记住，如果你没有给所有元素定位，那些没被定位的元素就会按照自动定位规则定位。这么做的结果可能恰好和你的目标一样，但如果一些元素在你预料之外的地方出现，先检查一下你有没有给它定位。

再者，记住你明确定位的元素是可以互相重叠的。有时你能用这点创造一些有趣的效果，但有时也会因为你定位错了线而导致不正确的重叠。Firefox Grid Highlighter 可以在你学习时给你帮助，特别是当你的网格比较复杂时。


CSS 网格布局和无障碍 - CSS：层叠样式表

CSS 网格布局和无障碍
============

我们这些做 web 开发多年的人和比我们更早入行的人，可能都觉得 CSS 网格有一点像曾经用过的“表格布局”。在 web 设计的早期，构建页面布局的方式是使用 HTML 表格，通过把设计分割成表格的单元格来创建布局。这比后来的“CSS 定位”的优势在于，可以利用表格显示能力提供的对齐和全高度的列。最大的负面影响在于它将设计和 HTML 标记绑在一起，经常会造成无障碍的问题。为了将设计摆到表格中，内容被打散了，如果用屏幕阅读器去读它，读出来的内容就是毫无意义的。

在转向 CSS 布局时，我们经常说 CSS 把内容标记与内容表现分离了。最终的目标是，我们可以创建一个语义和结构良好的文档，然后应用 CSS 来创建我们想要的布局。CSS Zen Garden 等网站展示了这种能力，CSS Zen Garden 提供的挑战是，对于一个具有固定标记的 HTML 页面，却能用 CSS 来创建各种独特的设计。

CSS 网格布局没有表格布局的那种问题，网格结构是在 CSS 中而不是在 HTML 标记中定义的。如果我们需要添加一个元素，我们可以使用一些没有语义的标记。理论上，网格可以帮助我们延续 CSS 的承诺——标记与表现分离，但是这个方案有可能会做得过火吗？是否会因为使用了网格而导致无障碍问题？

在 CSS 网格布局中重排内容
---------------

我们已经看到，网格使我们有能力以各种方式重新排列页面的内容。通过 `order` 属性来改变项目自动定位，可以使用 `grid-auto-flow: dense` 使项目在视觉上脱离 DOM 顺序，还可以使用网格模板区域的基于线的定位来定位项目，这些方法都不用考虑标记位于 HTML 源代码中的位置。

CSS 网格布局规范包括一个涵盖重新排序和无障碍的部分。该部分详细介绍了当使用网格布局对内容进行可视化重新排序时，规范期望浏览器执行的操作。

>
> 网格布局赋予了 web 开发者重新排列文档内容的强大能力，但是，这并不能取代 HTML 源代码中自身的排序。order 属性和网格定位不影响非可视媒体（例如语音）的排序。同样，可视化地重新排列网格项目不会影响顺序导航模式的默认遍历顺序（例如通过 TAB 键循环选取链接，参见 tabindex HTML5）。
>
>
>

虽然使用网格布局对内容进行了可视化重新排列，但是在通过屏幕阅读器或其他文本到语音的用户代理读取内容时，并不会改变项目的排列方式。另外，重新排序不会改变 tab 键顺序，这意味着使用键盘进行导航的用户，通过按 TAB 键来引导阅读顺序，但由于下一个项目是在源代码的下一行，而这个项目正好被重新排序过，那他就会从网站的顶部一下子跳转到网站的底部。

所以规范警告作者（CSSWG 称呼 web 开发者的术语）不要对内容重新排序。

>
> 作者必须仅把 order 和网格布局属性用于内容的视觉排序而非逻辑排序。使用这些功能执行逻辑重新排序的样式表是不符合标准的。
>
>
>

这在网格布局设计中意味着什么呢？

### 视觉的而非逻辑的排序

无论何时，当使用网格布局重新排序或使用 flex 布局重新排序时，只能执行视觉的重新排序。真实的源代码顺序是语音阅读器的顺序，以及文档的 Tab 键顺序。下面是一个非常简单的例子。

在这个例子中，用网格布局了一组包含链接的盒子，使用基于线的布局属性把 box1 放置在了网格的第 2 行。虽然 box1 看起来呈现为列表的第四个项目，但如果此时用 tab 链切换链接，仍然是从 box1 开始，因为它在源代码中排得最靠前。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}

.box1 {
  grid-column: 1;
  grid-row: 2;
}
```

```html
<div class="wrapper">
  <div class="box box1"><a href="">One</a></div>
  <div class="box box2"><a href="">Two</a></div>
  <div class="box box3"><a href="">Three</a></div>
  <div class="box box4"><a href="">Four</a></div>
  <div class="box box5"><a href="">Five</a></div>
</div>
```

规范声称在这种情况下，如果 box1 在此位置确的有逻辑上的意义，那就应该返回去修改源代码，而不是使用网格布局来重新排序。此例就是视觉的排序与逻辑的排序的对比，逻辑排序对于文档的意义和结构非常重要，一定要确保文档中的逻辑顺序正确。

### Firefox 中 flex 布局的排序 bug

Firefox 中一个久已存在的 bug 因此变得非常显眼。虽然这个问题在 Firefox 的 CSS 网格布局实现中不存在，但它确实暴露了一个我们在使用网格时需要考虑的问题。

目前，在使用 flex 布局时，Firefox 将遵循视觉顺序而不是逻辑顺序浏览文档。有人认为，这实际上是一个更好的方法——使 tab 键顺序遵循文档的视觉顺序。然而，事实证明，这是 Firefox 实现中的一个 bug。两种规范都声明逻辑顺序就是源文档的结构顺序，而 tab 键顺序和语音浏览器应遵循文档的逻辑顺序。

如何处理网格布局的无障碍？
-------------

从规范中我们知道需要确保文档内容的逻辑顺序。我们应该如何开发，才能对不同用户以及他们与页面的交互都保持良好的无障碍？

从结构化的、可访问的文档开始

网格布局意味着不需要改变文档源代码，就可以获得想要的布局。因此，开发页面的起点应该是一个结构良好的，可访问的源文档。正如 CSS 网格布局规范指出的，这通常也要求为最小的屏幕设备提供一个良好的文档结构。如果用户在移动设备上滚动长文档，那么用户优先要看到的内容也应在文档中位于优先的位置。

创建响应式的、自适应的网格

有了一个结构稳固的文档，就可以创建布局了，很可能要使用媒体查询来创建额外的列，并对不同的屏幕尺寸和设备改变布局。网格此时大有用武之地，例如，在移动设备上优先级不高的元素，在桌面设备上会被移到边栏中显示。此时的关键环节是要持续测试，一个非常简单的测试方法就是用 tab 键浏览文档。这个浏览顺序还有意义吗？检查是否有什么奇怪的从布局顶部跳到底部的情况，如果有的话，这就是一个信号，要赶快找找布局哪里出了问题。

回到源代码

如果在设计布局的过程中发现自己在使用网格重新定位元素的位置，就要考虑是否应该返回到文档并对逻辑顺序进行更改。使用 CSS 网格布局的一大好处是能够移动源文档中的项目以匹配逻辑顺序，而无需对布局进行大的更改。例如，对于基于 `float` 的布局，这是一个巨大的改进，其中文档的源代码非常重要，以便在不同的断点处获取布局。然而，作为开发人员，我们需要记得回到源代码并更新它以维护逻辑顺序。

网格和标记变平的危险
----------

CSS 网格布局中需要注意的另一个问题（在 CSS Flex 布局中程度较轻），是标记*变平*的诱惑。我们已经知道，一个项目要成为一个网格项目，它需是网格容器的直接子项目，因此，如果在网格容器中有一个 `<ul>` 元素，那么*这个* `ul` 是一个网格项目，但子元素 `<li>` 并不是网格项目。

如果 `display` 属性的 `subgrid` 值得以实现，则可以通过将 `ul` 元素声明为 *subgrid* 来使网格项目的这些子元素参与到整个网格布局中。目前唯一的解决方法是使用 `display：contents` 使 `ul` 生成的方框从 DOM 中消失。有关此相互影响的更多信息，请参阅本指南的网格布局与其他布局方法的关系一文及文中的 `display: contents` 部分。

由于对可互相影响的 `display: contents` 的支持有限，而且 subgrid 还没得到支持，所以当开发一个使用 CSS 网格布局的网站时，为了简单地创建布局，不可避免地要受到标签扁平化和移除语义元素的诱惑。例如，某些内容在语义上被标记为列表，但是为了通过 `display: grid` 将这些元素设置为容器的直接子元素，可能会决定用一组 `<div>` 标签来替代。要抵抗这种诱惑，找到不删除标记的设计方法。从一个结构良好的文档开始，是避免这个问题是一个好办法，当不得已去修改文档时，你就会意识到，你将仅是为了让布局工作而要删除语义元素！

延伸阅读
----

目前关于无障碍和 CSS 网格布局的资料并不多。许多问题与 CSS Flex 布局遇到的问题类似，也提出了使用 `flex-direction` 和 `order` 属性重新排序内容的方法。

依据文档源代码顺序进行可视化显示的概念在 *WCAG（无障碍网页内容指引）成熟标准技巧 - 技巧 C27* 中有详细描述。

作为一种开始思考这些问题的方式，当使用 CSS 网格布局时，建议阅读 Leonie Watson 的 *Flexbox & the Keyboard Navigation Disconnect。来自 ffconf 的 Leoie 的演示视频有助于了解屏幕阅读器如何使用 CSS 的视觉表示进行工作。Adrian Roselli 也发表了 tab order in various browsers——尽管这是在 Firefox 完全实现网格支持之前。*


利用 CSS 网格布局实现常用布局 - CSS：层叠样式表

利用 CSS 网格布局实现常用布局
=================

为了完善这组 CSS 网格布局指南，我将介绍几种不同的布局，它们演示了在使用网格布局进行设计时可以使用的一些不同技术。我们将看到一个使用 grid-template-areas 的示例，一个典型的 12 列灵活网格系统，以及一个使用自动布局的产品列表。正如你从这组示例中看到的，使用网格布局通常有不止一种方法来实现你想要的结果。选择对你正在解决的问题和需要实现的设计最有帮助的方法。

使用网格模板区域的响应式布局，包含 1 到 3 个流动列
----------------------------

许多网站都是这种布局的变体，有内容、边栏、页眉和页脚。在响应式设计中，你可能希望将布局显示为单个列，在某个断点添加侧栏，然后为更宽的屏幕引入三列布局。

![Image of the three different layouts created by redefining our grid at two breakpoints.](/zh-CN/docs/Web/CSS/CSS_grid_layout/Realizing_common_layouts_using_grids/11-responsive-areas.png)

我将使用我们在向导网格模板区域中了解到的命名模板区域来创建这个布局。

我的标记是一个容器，其中包含用于标题、页脚、主要内容、导航、边栏和打算放置广告的块的元素。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  max-width: 1024px;
  margin: 0 auto;
  font:
    1.2em Helvetica,
    arial,
    sans-serif;
}

.wrapper > \* {
  border: 2px solid #f08c00;
  background-color: #ffec99;
  border-radius: 5px;
  padding: 10px;
}

nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
```

```html
<div class="wrapper">
  <header class="main-head">The header</header>
  <nav class="main-nav">
    <ul>
      <li><a href="">Nav 1</a></li>
      <li><a href="">Nav 2</a></li>
      <li><a href="">Nav 3</a></li>
    </ul>
  </nav>
  <article class="content">
    <h1>Main article area</h1>
    <p>
      In this layout, we display the areas in source order for any screen less
      that 500 pixels wide. We go to a two column layout, and then to a three
      column layout by redefining the grid, and the placement of items on the
      grid.
    </p>
  </article>
  <aside class="side">Sidebar</aside>
  <div class="ad">Advertising</div>
  <footer class="main-footer">The footer</footer>
</div>
```

因为我们使用`grid-template-areas`来创建布局。在任何媒体查询之外，我需要命名区域。我们使用`grid-area` 属性命名区域。

```css
.main-head {
  grid-area: header;
}
.content {
  grid-area: content;
}
.main-nav {
  grid-area: nav;
}
.side {
  grid-area: sidebar;
}
.ad {
  grid-area: ad;
}
.main-footer {
  grid-area: footer;
}
```

这不会创建任何布局，但是我们的项目现在有了名称，我们可以使用它来创建布局。在任何媒体查询之外，我现在要为移动宽度设置布局。在这里，我保持源文件的顺序，试图避免源文件和显示之间的任何断开，就像向导网格布局和无障碍中描述的那样。我没有定义任何列或行跟踪，但是这种布局规定了单个列，并且将根据需要为隐式网格中的每个项目创建行。

```css
.wrapper {
  display: grid;
  grid-gap: 20px;
  grid-template-areas:
    "header"
    "nav"
    "content"
    "sidebar"
    "ad"
    "footer";
}
```

在设置了移动布局之后，我们将获得所有屏幕大小的这一列，现在我们可以添加一个媒体查询并重新定义布局，以满足屏幕空间足够显示两列的情况。

```css
@media (min-width: 500px) {
  .wrapper {
    grid-template-columns: 1fr 3fr;
    grid-template-areas:
      "header header"
      "nav nav"
      "sidebar content"
      "ad footer";
  }
  nav ul {
    display: flex;
    justify-content: space-between;
  }
}
```

你可以看到布局在`grid-template-areas`的值中成形。 `header` 跨越两个列轨道，就像 `nav` 一样。在第三行轨道中，我们在 `content` 旁边有 `sidebar` 。在第四行轨道，我选择了放置我的广告内容 - 所以它出现在侧边栏下，然后 `footer` 旁边的内容。我在导航栏上使用了一个 flexbox 来显示它。

现在我可以添加最后一个断点来移动到三列布局。

```css
@media (min-width: 700px) {
  .wrapper {
    grid-template-columns: 1fr 4fr 1fr;
    grid-template-areas:
      "header header header"
      "nav content sidebar"
      "nav content ad"
      "footer footer footer";
  }
  nav ul {
    flex-direction: column;
  }
}
```

三列布局有两个 1fr 单元侧列和一个中间列，轨道大小为 4fr。这意味着容器中的可用空间被划分为 6 个部分，并按照我们的三个轨道的比例分配—每个轨道的一个部分位于侧列，四个部分位于中心。

在这个布局中，我在左边的列中显示导航，旁边是内容。在右边栏我们有侧边栏，在它下面是广告。页脚现在横跨布局的底部。然后我使用一个 flex xbox 将导航显示为一个列。

这是一个简单的示例，但是演示了如何使用网格布局来为不同的断点重新安排布局。具体来说，我正在更改广告块的位置，这在不同的列设置中是合适的。我发现这种命名区域的方法在原型制作阶段非常有用，很容易处理元素的位置。你可以始终以这种方式开始使用 grid 进行原型设计，即使由于访问你站点的浏览器的原因，你不能在生产中完全依赖它。

灵活的 12 列布局
----------

如果你使用过许多框架或网格系统之一，那么你可能已经习惯了将站点布置在 12 或 16 列的灵活网格上。我们可以使用 CSS 网格布局创建这种类型的系统。作为一个简单的例子，我正在创建一个 12 列的灵活网格，它有 12 个 1fr-unit 列轨道，它们都有一个名为`col-start` 的起始行。这意味着我们将拥有 12 条名为 `col-start` 的网格线。
```

.wrapper {
  max-width: 1024px;
  margin: 0 auto;
  font:
    1.2em Helvetica,
    arial,
    sans-serif;
}
.wrapper > \* {
  border: 2px solid #f08c00;
  background-color: #ffec99;
  border-radius: 5px;
  padding: 10px;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(12, [col-start] 1fr);
  grid-gap: 20px;
}
```

为了演示这个网格系统是如何工作的，我在包装器中包含了 4 个子元素。

```html
<div class="wrapper">
  <div class="item1">Start column line 1, span 3 column tracks.</div>
  <div class="item2">
    Start column line 6, span 4 column tracks. 2 row tracks.
  </div>
  <div class="item3">Start row 2 column line 2, span 2 column tracks.</div>
  <div class="item4">
    Start at column line 3, span to the end of the grid (-1).
  </div>
</div>
```

然后，我可以使用命名行和 span 关键字将它们放到网格上。

```css
.item1 {
  grid-column: col-start / span 3;
}
.item2 {
  grid-column: col-start 6 / span 4;
  grid-row: 1 / 3;
}
.item3 {
  grid-column: col-start 2 / span 2;
  grid-row: 2;
}
.item4 {
  grid-column: col-start 3 / -1;
  grid-row: 3;
}
```

正如命名行指南中所述，我们使用命名行来放置项目。因为我们有 12 行名称相同，所以我们使用名称，然后是行索引。如果你喜欢并完全避免使用命名行，也可以使用行索引本身。

我没有设置结束行号，而是选择使用 span 关键字表示这个元素应该跨多少个轨道。我喜欢这种方法，因为在使用多列布局系统时，我们通常根据网格的轨迹数量来考虑块，并根据不同的断点进行调整。要查看块如何与轨道对齐，请使用 Firefox Grid Inspector (en-US). 。它清楚地展示了我们的项目是如何放置的。

![Showing the items placed on the grid with grid tracks highlighted.](/zh-CN/docs/Web/CSS/CSS_grid_layout/Realizing_common_layouts_using_grids/11-grid-inspector-12col.png)

与你以前可能使用过的网格系统上的网格布局的工作方式有一些关键区别。如你所见，我们不需要添加任何标记来创建行，网格系统需要这样做来阻止元素弹出到上面的行中。使用 CSS 网格布局，我们可以将内容放入行中，如果行是空的，则它们不会上升到上面的行中。由于这种严格的列和行布局，我们也可以很容易地在布局中留出空白。我们也不需要特殊的类来拉或推东西，将它们缩进网格。我们需要做的就是指定项目的开始和结束行。

使用 12 列系统构建布局
-------------

为了了解这种布局方法在实践中是如何工作的，我们可以使用 12 列网格系统创建与使用`grid-template-areas`创建的布局相同的布局。我开始使用与网格模板区域示例相同的标记。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  max-width: 1024px;
  margin: 0 auto;
  font:
    1.2em Helvetica,
    arial,
    sans-serif;
}

.wrapper > \* {
  border: 2px solid #f08c00;
  background-color: #ffec99;
  border-radius: 5px;
  padding: 10px;
}

nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
```

```html
<div class="wrapper">
  <header class="main-head">The header</header>
  <nav class="main-nav">
    <ul>
      <li><a href="">Nav 1</a></li>
      <li><a href="">Nav 2</a></li>
      <li><a href="">Nav 3</a></li>
    </ul>
  </nav>
  <article class="content">
    <h1>Main article area</h1>
    <p>
      In this layout, we display the areas in source order for any screen less
      that 500 pixels wide. We go to a two column layout, and then to a three
      column layout by redefining the grid, and the placement of items on the
      grid.
    </p>
  </article>
  <aside class="side">Sidebar</aside>
  <div class="ad">Advertising</div>
  <footer class="main-footer">The footer</footer>
</div>
```

然后，我可以设置网格，如上面的示例 12 列布局。

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(12, [col-start] 1fr);
  grid-gap: 20px;
}
```

我们将再次使其成为响应式布局，不过这次使用的是命名行。每个断点都将使用一个 12 列的网格，但是，根据屏幕的大小，项目将跨越的轨道数量会发生变化。

我们首先启动移动设备，对于最窄的屏幕，我们想要的只是保持项目的源顺序，并且所有项目都跨越网格。

```css
.wrapper > \* {
  grid-column: col-start / span 12;
}
```

在下一个断点处，我们希望转移到两列布局。我们的标题和导航仍然跨整个网格，所以我们不需要为它们指定任何位置。侧边栏从第一行 colstart 开始，共 3 行。它在第 3 行之后，因为标题和导航位于前两行轨道中。

ad 面板位于边栏下面，因此从网格行 4 开始。然后我们有内容和页脚，从 colstart 4 开始，跨越 9 个轨道，把它们带到网格的末端。

```css
@media (min-width: 500px) {
  .side {
    grid-column: col-start / span 3;
    grid-row: 3;
  }
  .ad {
    grid-column: col-start / span 3;
    grid-row: 4;
  }
  .content,
 .main-footer {
    grid-column: col-start 4 / span 9;
  }
  nav ul {
    display: flex;
    justify-content: space-between;
  }
}
```

最后，我们转到这个布局的三列版本。标题继续横跨整个网格，但现在导航将向下移动，成为第一个侧边栏，其中包含内容，然后是旁边的侧边栏。页脚现在也跨整个布局。

```css
@media (min-width: 700px) {
  .main-nav {
    grid-column: col-start / span 2;
    grid-row: 2 / 4;
  }
  .content {
    grid-column: col-start 3 / span 8;
    grid-row: 2 / 4;
  }
  .side {
    grid-column: col-start 11 / span 2;
    grid-row: 2;
  }
  .ad {
    grid-column: col-start 11 / span 2;
    grid-row: 3;
  }
  .main-footer {
    grid-column: col-start / span 12;
  }
  nav ul {
    flex-direction: column;
  }
}
```

网格检查器再次帮助我们了解布局是如何形成的。

![Showing the layout with grid tracks highlighted by the grid inspector.](/zh-CN/docs/Web/CSS/CSS_grid_layout/Realizing_common_layouts_using_grids/11-grid-inspector-12col-layout.png)

在创建这个布局时需要注意的一点是，我们不需要在每个断点显式地定位网格上的每个元素。我们能够继承为早期断点设置的位置——这是移动优先”的优势。我们还可以利用网格自动布局。通过保持元素的逻辑顺序，自动布局为我们将项目放到网格上做了很多工作。在本指南的最后一个示例中，我们将创建完全依赖自动布局的布局。

自动放置的产品列表
---------

许多布局基本上是一组“卡片”——产品列表、图像库等等。网格可以使创建这些清单变得非常容易，而且无需添加媒体查询就可以响应。在下一个例子中，我将 CSS Grid 和 flexbox 布局相结合，以创建一个简单的产品列表布局。

我的列表的标记是一个无序的项目列表。每个项目都包含一个标题、一些不同高度的文本和对 action 链接的调用。

```html
<ul class="listing">
  <li>
    <h2>Item One</h2>
    <div class="body"><p>The content of this listing item goes here.</p></div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
  <li>
    <h2>Item Two</h2>
    <div class="body"><p>The content of this listing item goes here.</p></div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
  <li class="wide">
    <h2>Item Three</h2>
    <div class="body">
      <p>The content of this listing item goes here.</p>
      <p>This one has more text than the other items.</p>
      <p>Quite a lot more</p>
      <p>Perhaps we could do something different with it?</p>
    </div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
  <li>
    <h2>Item Four</h2>
    <div class="body"><p>The content of this listing item goes here.</p></div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
  <li>
    <h2>Item Five</h2>
    <div class="body"><p>The content of this listing item goes here.</p></div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
</ul>
```

```
\* {
  box-sizing: border-box;
}
img {
  max-width: 100%;
  display: block;
}
body {
  font:
    1.2em Helvetica,
    arial,
    sans-serif;
}
a:link,
a:visited {
  text-decoration: none;
  color: #f08c00;
}

h2 {
  background-color: #f08c00;
  color: #fff;
  text-align: center;
  margin: 0;
  padding: 20px;
}
```

我们将创建一个具有灵活数量的灵活列的网格。我希望它们永远不要小于 200 像素，然后平等地共享任何可用的剩余空间——所以我们总是得到相同宽度的列轨迹。我们使用 minmax() 函数实现了这一点，该函数是用于轨道大小的重复表示法。

```css
.listing {
  list-style: none;
  margin: 2em;
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
```

一旦我添加了这个 CSS，项目就开始以网格的形式展开。如果我让窗口变小或变宽，列跟踪的数量就会发生变化，而不需要使用媒体查询添加断点并重新定义网格。

然后，我就可以使用 flex touch 来整理这些盒子的内部结构。我将列表项设置为 `display: flex` 和 `flex-direction` 设置为 `column`。然后，我可以在 `.cta` 上使用自动边界将这个工具条推到盒子底部。

```css
.listing li {
  border: 1px solid #ffe066;
  border-radius: 5px;
  display: flex;
  flex-direction: column;
}
.listing .cta {
  margin-top: auto;
  border-top: 1px solid #ffe066;
  padding: 10px;
  text-align: center;
}
.listing .body {
  padding: 10px;
}
```

这是我使用 flexbox 而不是 grid 的一个关键原因，如果我只是在一个维度上调整或发布一些东西，那就是一个 flexbox 用例。

使用 dense 关键字避免间隙
----------------

这一切现在看起来相当完整，然而我们有时拥有这些卡片，其中包含的内容比其他卡片多得多。让它们跨越两条轨道可能很好，这样它们就不会那么高了。我在较大的项目上有一个 wide 类，我添加了一个规则`grid-column-end` (en-US)，其值为 span 2。现在，当 grid 遇到这个项目时，它将为它分配两个轨道。在某些断点处，这意味着我们将在网格中得到一个缺口——在这个缺口中没有空间放置一个双轨项目。

![The layout has gaps as there is not space to layout a two track item.](/zh-CN/docs/Web/CSS/CSS_grid_layout/Realizing_common_layouts_using_grids/11-grid-auto-flow-sparse.png)

我可以通过设置`grid-auto-flow``: dense` 在网格容器上设置稠密，从而使网格填充这些空白。但是，在这样做时要小心，因为它会使项目偏离其逻辑源顺序。你应该只在项目没有设置顺序时才这样做——并且要注意源文件后面的选项卡顺序的问题，而不是重新排序的显示。
```

<ul class="listing">
  <li>
    <h2>Item One</h2>
    <div class="body"><p>The content of this listing item goes here.</p></div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
  <li>
    <h2>Item Two</h2>
    <div class="body"><p>The content of this listing item goes here.</p></div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
  <li class="wide">
    <h2>Item Three</h2>
    <div class="body">
      <p>The content of this listing item goes here.</p>
      <p>This one has more text than the other items.</p>
      <p>Quite a lot more</p>
      <p>Perhaps we could do something different with it?</p>
    </div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
  <li>
    <h2>Item Four</h2>
    <div class="body"><p>The content of this listing item goes here.</p></div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
  <li>
    <h2>Item Five</h2>
    <div class="body"><p>The content of this listing item goes here.</p></div>
    <div class="cta"><a href="">Call to action!</a></div>
  </li>
</ul>
```

```
\* {
  box-sizing: border-box;
}
img {
  max-width: 100%;
  display: block;
}
body {
  font:
    1.2em Helvetica,
    arial,
    sans-serif;
}
a:link,
a:visited {
  text-decoration: none;
  color: #f08c00;
}

h2 {
  background-color: #f08c00;
  color: #fff;
  text-align: center;
  margin: 0;
  padding: 20px;
}

.listing li {
  border: 1px solid #ffe066;
  border-radius: 5px;
  display: flex;
  flex-direction: column;
}
.listing .cta {
  margin-top: auto;
  border-top: 1px solid #ffe066;
  padding: 10px;
  text-align: center;
}
.listing .body {
  padding: 10px;
}
```

```css
.listing {
  list-style: none;
  margin: 2em;
  display: grid;
  grid-gap: 20px;
  grid-auto-flow: dense;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
.listing .wide {
  grid-column-end: span 2;
}
```

这种技术使用 auto-placement 一些规则应用于某些物品是非常有用的，并且可以帮助你处理的内容是由 CMS 例如，输出有重复项，或许可以添加一个类特定的呈现为 HTML。

Further exploration
-------------------

学习使用网格布局的最佳方法是继续构建我们在这里介绍的示例。选择一些你通常使用选择的框架构建的东西，或者使用浮动构建的东西，看看是否可以使用 grid 构建它。不要忘记寻找用当前方法无法构建的示例。这可能意味着从杂志或其他非网络资源中获取灵感。网格布局提供了我们以前没有过的可能性，我们不需要绑定到相同的旧布局来使用它。

* 有关灵感，请参阅 Layout Labs from Jen Simmons, 她一直在创建基于一系列资源的布局。
* 有关其他常见布局模式，请参见 Grid by Example, 这里有许多网格布局的小例子，也有一些较大的 UI 模式和完整的页面布局。


CSS 网格布局中的自动定位 - CSS：层叠样式表

CSS 网格布局中的自动定位
==============

为了精确地把项目摆放到网格中，CSS 网格布局规范还包含另外一组规则，用来约定当部分或全部子项目没有被明确指定位置时该如何处理。你会发现针对含有数个项目的网格，实际上最简单的方式就是使用自动定位。

默认定位
----

如果没有为项目指定位置信息，它们就会把自己摆放在网格中，每个单元格中放一个。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
```

```html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>
```

自动定位的默认规则
---------

正如上例所示，所有子项目都会把自己摆放到网格中，每个单元格中放一个。默认的流向是按行排列项目，网格会首先尝试在第 1 行的每个单元格中摆放项目。如果已经通过 `grid-template-rows` 属性创建了其他行，网格就会继续把项目摆放到这些行中。如果在显式的网格中没有足够的行用来摆放所有的项目，*隐式*的新行就会被创建出来。

### 调整网格中隐式行的大小

在默认情况下，网格中被自动创建的隐式行的尺寸是自适应大小的，也就是说它们会包含所有属于它们的内容，而不会让内容溢出。

不过你可以通过 `grid-auto-rows` 属性来控制它们的大小。为了让所有的行都是 100 像素高，可以像下面这样做：
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  grid-auto-rows: 100px;
}
```

### 使用 minmax() 调整行的大小

也可以为 `grid-auto-rows` 设置 `minmax()` 值，这会让创建出的行保持一个最小尺寸，而且能够自动加高以适应更多的内容。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>
    Four <br />This cell <br />Has extra <br />content. <br />Max is auto
    <br />so the row expands.
  </div>
  <div>Five</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  grid-auto-rows: minmax(100px, auto);
}
```

### 使用轨道列表调整行的大小

也可以向 `grid-auto-rows` 属性传入一个轨道列表，行的大小就会按轨道列表重复设置。在下例中，轨道列表声明了一个 100 像素的行和第二个 200 像素的行，当内容很多时网格就会自动创建足够多的隐式行来容纳内容。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  grid-auto-rows: 100px 200px;
}
```

### 按列自动定位

网格也可以按列来自动定位项目，只要设置 `grid-auto-flow` 的属性值为 `column` 即可。此时网格将根据已定义的 `grid-template-rows` 按列摆放项目，当一列中的项目排满，就继续排到下一列中，或排到一个新创建的隐式列中。因为显式定义了行轨道，所以列轨道是自适应大小的，同样地，也可以像 `grid-auto-rows` 那样通过设置 `grid-auto-columns` 来控制隐式列的尺寸。

在下面的例子中，创建了一个行高为 200 像素的三个行轨道的网格，按列优先自动排列，先创建一个 300 像素宽的列，接着是一个 100 像素宽的列，直至创建出足够多的列来容纳全部项目。

```css
.wrapper {
  display: grid;
  grid-template-rows: repeat(3, 200px);
  gap: 10px;
  grid-auto-flow: column;
  grid-auto-columns: 300px 100px;
}
```

```
\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
</div>
```

被自动定位的项目的顺序
-----------

网格中包含的多个项目可以混合定位，一些项目依靠明确的位置，而另一些则依靠自动定位。混合定位的用途在于，如果你有一个文档，其中部分项目已经定位，其他项目只要按顺序排列就行了，而无需为所有项目都指定绝对的位置。规范中用了很长的章节来详细描述网格项目的定位算法，好在我们只需要记住几条简单的规则就够了。

### 为修改过顺序的文档排序

对没有指定网格位置的项目进行定位，在标准中被称为“为修改过顺序的文档排序”。这意味着如果完全使用 `order` 属性，项目的顺序将根据 `order` 属性重新排序，而不是它们在 DOM 中的顺序，要不然它们本来是按在 DOM 中出现的顺序排列的。

### 含有定位属性的项目

网格首先要做的是让每个项目都有一个位置。在下面的例子中，一共有 12 个网格项目，项目 2 和项目 5 已经通过使用基于线定位的方法确定了它们在网格中的位置。仔细观察网格空间中这两个已定位的项目和那些自动定位的项目。自动定位的项目将按在 DOM 中的顺序从已定位项目的前面开始摆放，虽然有两个项目已经事先定位好，但其他项目不是从已经定位的项目之后才开始摆放的。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
  <div>Nine</div>
  <div>Ten</div>
  <div>Eleven</div>
  <div>Twelve</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  gap: 10px;
}
.wrapper div:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}
```

### 对占据多条轨道的项目的处理规则

在使用定位属性时仍然可以利用自动定位功能。在下面的例子中，有几个项目被设置为在行和列上都占据两条轨道，这是通过把 `grid-column-end` (en-US) 和 `grid-row-end` (en-US) 属性都设置为 `span 2` 实现的，这么写的意思是项目的开始线由自动定位规则确定，但是结束线将跨越两条轨道。

请观察网格中是如何被留出缺口的，因为对于自动定位的项目，如果轨道的大小不适合放入一个项目，这个项目就会被移动到下一行，直至它找到了可以容纳它的空间。
```

\* {
  box-sizing: border-box;
}
.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
  <div>Nine</div>
  <div>Ten</div>
  <div>Eleven</div>
  <div>Twelve</div>
</div>
```

```css
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  gap: 10px;
}
.wrapper div:nth-child(4n + 1) {
  grid-column-end: span 2;
  grid-row-end: span 2;
  background-color: #ffa94d;
}
.wrapper div:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}
```

### 填充缺口

至此，除了我们明确定位过的项目，其他项目一般都会被网格自动处理并且保持它们在 DOM 中的顺序，这正是一般情况下我们想要的结果。比如你设计了一个表单，当然不想让标签和别的表单元素因为要填充缺口而使表单变得前后错乱。不过有时候要布局的项目并没有逻辑顺序，所以我们希望能够创建一种没有缺口的布局。

实现这个效果的方法是在网格容器的 `grid-auto-flow` 属性值中加入 `dense` 关键字。这和此前把网格流向改为列优先时设置值为 `column` 的是同一个属性，所以在列优先流向时，要设置 2 个值 `grid-auto-flow: column dense`。

经过以上设置，网格就会回填缺口，以前网格会遗留下缺口，而现在它会为此前的缺口找到适合它的项目，然后把项目从 DOM 中拿出来再放到缺口中去。对于已经重新指定过顺序的网格，这样做不会改变项目之间原有的逻辑顺序，比如对于 Tab 键的顺序仍然与文档的顺序相同。在后面的文章中我们会讨论网格布局潜在的可用性问题，此外你应该意识到，使用这个功能会让 DOM 中看到的顺序与实际显示的顺序不一致，它们两者之间的联系会被打破。
```

\* {
  box-sizing: border-box;
}
.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}

.wrapper > div {
  border: 2px solid #ffa94d;
  border-radius: 5px;
  background-color: #ffd8a8;
  padding: 1em;
  color: #d9480f;
}
```

```html
<div class="wrapper">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
  <div>Four</div>
  <div>Five</div>
  <div>Six</div>
  <div>Seven</div>
  <div>Eight</div>
  <div>Nine</div>
  <div>Ten</div>
  <div>Eleven</div>
  <div>Twelve</div>
</div>
```

```css
.wrapper div:nth-child(4n + 1) {
  grid-column-end: span 2;
  grid-row-end: span 2;
  background-color: #ffa94d;
}
.wrapper div:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}
.wrapper {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: 100px;
  gap: 10px;
  grid-auto-flow: dense;
}
```

### 匿名网格项目

标准中还提到了匿名网格项目。当有一些字符串或文本被包含在网格容器中，但却没有被其他元素包装，它们就会被创建为匿名网格项目。下面的例子，假设容器的类 `grid` 设置了 `display: grid` 属性，那么网格中就有三个网格项目，第一个就是匿名项目，因为它没有用标签分隔，所以会被自动定位规则处理。另 2 个放在 div 中的项目，它们可以被自动定位，也可以通过网格的定位属性来定位。

```html
<div class="grid">
  I am a string and will become an anonymous item
  <div>A grid item</div>
  <div>A grid item</div>
</div>
```

匿名项目被自动定位是因为没有办法选定它们。所以如果在网格中有一些因故未被包装的文本，要小心它们可能会出现在网格的不可预期的位置，因为它们的位置完全靠自动定位规则来确定。

### 自动定位实例

当要展示一组相互之间没有逻辑顺序的项目，比如一组照片或产品列表，自动定位就非常有用了，这时你可以使用密集填充模式来填满网格的缺口。在下面的图片墙例子中，有横幅图片和纵幅图片，我们为所有横幅图片设置了样式 `landscape`，让它占据两列，然后使用 `grid-auto-flow: dense` 去创建一个密集填充的网格。

尝试移除 `grid-auto-flow: dense` 这一行，以查看内容重排后在布局中留下的缺口。

自动定位还可以帮你布局有逻辑顺序的界面元素。下面的术语列表就是一个示例。为定义列表添加样式是一个有趣的挑战，即它的结构是扁平的，没有把成组的 `dt` 和 `dd` 元素包装起来。在示例中，我们使用自动定位来定位项目，另外还通过样式类把 `dt` 摆放在第 1 列，把 `dd` 摆放在第 2 列，以便让术语显示在一边，术语的定义显示在另一边，而不用管它们各有多少个。
```

\* {
  box-sizing: border-box;
}

.wrapper {
  border: 2px solid #f76707;
  border-radius: 5px;
  background-color: #fff4e6;
}
```

```html
<div class="wrapper">
  <dl>
    <dt>Mammals</dt>
    <dd>Cat</dd>
    <dd>Dog</dd>
    <dd>Mouse</dd>
    <dt>Fish</dt>
    <dd>Guppy</dd>
    <dt>Birds</dt>
    <dd>Pied Wagtail</dd>
    <dd>Owl</dd>
  </dl>
</div>
```

```css
dl {
  display: grid;
  grid-template-columns: auto 1fr;
  max-width: 300px;
  margin: 1em;
  line-height: 1.4;
}
dt {
  grid-column: 1;
  font-weight: bold;
}
dd {
  grid-column: 2;
}
```

自动定位做不了什么？
----------

前面已经讨论过，目前我们还不能选定网格中的任意单元格上的任意项目，在上一篇文章的最后一节讲到如何为多条线定义相同名字，但是当这两个功能在一起执行时就会带来问题。这个问题被称为“自动定位的项目违反了后续第 n 个同名行的规则”，网格的自动定位算法将会跳过一些不该跳过的行。这个问题在 CSSWG 的 GitHub 仓库中已经被提出了，欢迎你去添加自己的用例。

可能你在使用自动定位或网格布局的其他功能时也会遇到问题，如果遇到了，请把它们抛出来，或者作为用例追加到已有问题上，一方面便于解决，另一方面也会帮助规范在未来的新版本变得更好。


repeating-linear-gradient() - CSS：层叠样式表

repeating-linear-gradient()
===========================

CSS 函数 **`repeating-linear-gradient()`** 创建一个由重复线性渐变组成的 `<image>`，类似于 `linear-gradient()` (en-US)，并且采用相同的参数，但是它会在所有方向上重复渐变以覆盖其整个容器。这个函数的结果是 `<gradient>` 数据类型的对象，此对象是一种特殊的 `<image>` 类型。

尝试一下
----

重复渐变的长度是第一个色标和最后一个色标之间的距离。如果第一种颜色没有色标长度，则色标长度默认为 0。每次重复时，色标的位置都会以基本线性渐变长度的倍数移动。因此，每个结束色标的位置都会与起始色标的位置重合；如果色值不同，就会产生鲜明的视觉过渡。可以通过重复第一种颜色值作为最后一种颜色值来改变这种情况。

与其他渐变一样，线性重复渐变没有内在尺寸，也就是说，它没有固有或首选的尺寸，也没有首选的比例，其实际大小取决于所应用的元素的大小。

由于 `<gradient>` 属于 `<image>` 数据类型，因此只能用在可以使用 `<image>` 的地方。因此，`repeating-linear-gradient()` 在`background-color` 以及其他使用 `<color>` 数据类型上不起作用。

语法
--

```css
/\* 一个倾斜 45 度的重复线性渐变，
 从蓝色开始渐变到红色 \*/
repeating-linear-gradient(45deg, blue, red);

/\* 一个从右下角到左上角的重复线性渐变，
 从蓝色开始渐变到红色 \*/
repeating-linear-gradient(to left top, blue, red);

/\* 一个由下至上的重复线性渐变，
 从蓝色开始，40% 后变绿，
 最后渐变到红色 \*/
repeating-linear-gradient(0deg, blue, green 40%, red);

/\* 从左到右重复五次的渐变，从红色开始，然后变绿，再变回红色 \*/
repeating-linear-gradient(to right, red 0%, green 10%, red 20%);
```

### 值

`<side-or-corner>`

渐变线的起始点位置。如果指定了，则包含 `to` 和两个关键字：一个指定水平位置（`left` 或 `right`），另一个指定竖直位置（`top` 或 `bottom`）。关键字的先后顺序无影响。如果没有指定，则默认为 `to bottom`。

`to top`、`to bottom`、`to left` 和 `to right` 分别等价于 `0deg`、`180deg`、`270deg` 和 `90deg`。其余值会被转换为角度。

`<angle>`

渐变线的方向的角度。`0deg` 等价于 `to top`，增加值相当于顺时针旋转。

`<linear-color-stop>`

色标（color stop）的 `<color>` 值，然后是一个或两个可选的色标位置（沿渐变轴的 `<percentage>` 或 `<length>`）。百分比值 `0%`，或者长度值 `0`，代表渐变的开始，`100%` 代表 100% 的图像尺寸，也就是说渐变不会重复。

`<color-hint>`

颜色提示（color-hint）是一种插值提示，定义了渐变色在相邻色标之间的渐变方式。长度定义了渐变色应在两个色标之间的哪个点到达颜色过渡的中点。如果省略此值，颜色过渡的中点就是两个色标之间的中点。

**备注：** CSS 渐变中的色标的渲染与 SVG 渐变中的色标遵循相同的规则。

### 形式语法
```

<repeating-linear-gradient()> =
  repeating-linear-gradient( [ <linear-gradient-syntax> ] )

<linear-gradient-syntax> =
  [ <angle> | to <side-or-corner> ]? , <color-stop-list>

<side-or-corner> =
  [ left | right ]  ||
  [ top | bottom ]

<color-stop-list> =
  <linear-color-stop> , [ <linear-color-hint>? , <linear-color-stop> ]#

<linear-color-stop> =
  <color> <length-percentage>?

<linear-color-hint> =
  <length-percentage>

<length-percentage> =
  <length>      |
  <percentage>

```

示例
--

### 斑马条纹
```

body {
  width: 100vw;
  height: 100vh;
}
```

```css
body {
  background-image: repeating-linear-gradient(
    -45deg,
    transparent,
    transparent 20px,
    black 20px,
    black 40px
  );
  /\* 包括多个色标长度 \*/
  background-image: repeating-linear-gradient(
    -45deg,
    transparent 0 20px,
    black 20px 40px
  );
}
```

### 十个重复的水平线
```

body {
  width: 100vw;
  height: 100vh;
}
```

```css
body {
  background-image: repeating-linear-gradient(
    to bottom,
    rgb(26, 198, 204),
    rgb(26, 198, 204) 7%,
    rgb(100, 100, 100) 10%
  );
}
```

由于最后一个色标是 10%，且渐变是竖直的，因此重复渐变中的每个渐变都是高度的 10%，正好满足 10 个水平线。

**备注：** 更多示例请参见使用 CSS 渐变。

规范
--

| Specification |
| --- |
| CSS Images Module Level 3 # repeating-gradients |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 使用 CSS 渐变
* 其他渐变函数：`linear-gradient()`、`radial-gradient()`、`repeating-radial-gradient()`、`conic-gradient()`、`repeating-conic-gradient()` (en-US)
* `<image>`
* `image()` (en-US)
* `element()`
* `image-set()` (en-US)
* `cross-fade()` (en-US)


radial-gradient() - CSS：层叠样式表

radial-gradient()
=================

**`radial-gradient()`** CSS 函数创建一个图像，该图像由从原点辐射的两种或多种颜色之间的渐进过渡组成，其形状可以是圆形或椭圆形。函数的结果是 `<gradient>` 数据类型的对象，此对象是一种特殊的 `<image>` 类型。

尝试一下
----

语法
--

```css
/\* 在容器中心的渐变，从红色开始，变成蓝色，最后变成绿色 \*/
radial-gradient(circle at center, red 0, blue, green 100%)
```

径向渐变通过指定渐变的中心（0% 椭圆所在的位置）和*结束形状*（100% 椭圆）的大小和形状来指定。

值
-

`<position>`

渐变的位置，和解析 `background-position` 或者 `transform-origin` 的方式相同。如果没有指定，默认为 `center`。

`<ending-shape>`

渐变的结束形状。值可以是 `circle`（圆形，渐变的形状是一个半径不变的正圆）或 `ellipse`（椭圆，渐变形状是轴对称椭圆）。如果没有指定，默认为 `ellipse`。

`<size>`

确定渐变结束形状的大小。如果省略，则默认为最远角（farthest-corner）。它可以显式给出，也可以通过关键字给出。就关键字定义而言，渐变框边缘应视为向两个方向无限延伸，而不是有限线段。

对于它们的 `<size>`，圆形和椭圆渐变都接受以下关键字：

| 关键字 | 描述 |
| --- | --- |
| `closest-side` | 渐变结束形状如果是圆形，与容器距离渐变中心点最近的一边相切，如果是椭圆，则与距离渐变中心点最近的垂直和水平边相切。 |
| `closest-corner` | 渐变结束形状与容器距离渐变中心点最近的一个角相交。 |
| `farthest-side` | 类似于 `closest-side`，但是结束形状与容器距离渐变中心点最远的一边（或最远的垂直和水平边）相切。 |
| `farthest-corner` | 默认值，渐变的结束形状与容器距离渐变中心点最远的一个角相交。 |

如果 `<ending-shape>` 被指定为 `circle`，则可以为大小指定一个 `<length>` 值，它明确了圆的半径。负值是无效的。

如果 `<ending-shape>` 被指定为 `ellipse`，则可以使用带有两个值的 `<length-percentage>` 来指定椭圆的大小。第一个值表示水平半径，第二个值表示垂直半径。百分比值是相对于渐变框在相应维度上的大小的。负值是无效的。

如果 `<ending-shape>` 关键词被省略，渐变形状会由给定的大小决定。一个 `<length>` 产生圆，两个 `<length-percentage>` 单位的值产生椭圆。一个 `<percentage>` 值是无效的。

`<linear-color-stop>`

色标（color stop）的 `<color>` 值，然后是一个或两个可选的色标位置（沿渐变轴的 `<percentage>` 或 `<length>`）。百分比值 `0%`，或者长度值 `0`，代表渐变的中心；值 `100%` 表示结束形状与虚拟渐变射线的交点。两者之间的百分比值线性定位在渐变射线上。包含两个色标位置相当于在两个位置上声明了两个颜色相同的色标。

`<color-hint>`

颜色提示（color-hint）是一个插值提示，定义了渐变色在相邻色标之间的渐变方式。这个长度定义了渐变色应在两个色标之间的哪个点到达颜色过渡的中点。如果省略该值，颜色过渡的中点就是两个色标之间的中点。

描述
--

与其他渐变一样，径向渐变没有内在尺寸，也就是说，它没有固有或首选的尺寸，也没有首选的比例，其实际大小取决于所应用的元素的大小。

如要创建重复的径向渐变来填充容器，请使用 `repeating-radial-gradient()` 函数替代。

由于 `<gradient>` 属于 `<image>` 数据类型，因此只能用在能使用 `<image>` 的地方。因此，`radial-gradient()` 在 `background-color` 及其他使用 `<color>` 数据类型的属性上不起作用。

径向渐变的合成
-------

![解释径向渐变的图：虚拟辐射线从中点开始是水平的。椭圆渐变，及其结束形状，与所声明的框具有相同的长宽比。](/zh-CN/docs/Web/CSS/gradient/radial-gradient/radial_gradient.png)

径向渐变由其*中心点*、*结束形状*轮廓、*两个及以上色标*定义而成。

要创建平滑的渐变，`radial-gradient()` 函数绘制了一系列从中心点放射到*结束形状*（甚至可能超出范围）的同心轮廓。结束形状可以是圆形或椭圆形。

色标位于*虚拟渐变射线*（virtual gradient ray）上，该渐变射线从中心点水平向右延伸。基于百分比的色标位置是相对于结束形状和此渐变射线之间的交点（代表 `100％`）。每个形状都是单个颜色，并由其相交的渐变射线上的颜色确定。

形式语法
----
```

<radial-gradient()> =
  radial-gradient( [ <radial-gradient-syntax> ] )

<radial-gradient-syntax> =
  [ <radial-shape> || <radial-size> ]? [ at <position> ]? , <color-stop-list>

<radial-shape> =
  circle   |
  ellipse

<radial-size> =
  <radial-extent>               |
  <length [0,∞]>                |
  <length-percentage [0,∞]>{2}

<position> =
  [ left | center | right | top | bottom | <length-percentage> ]  |
  [ left | center | right ] && [ top | center | bottom ]  |
  [ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ]  |
  [ [ left | right ] <length-percentage> ] && [ [ top | bottom ] <length-percentage> ]

<color-stop-list> =
  <linear-color-stop> , [ <linear-color-hint>? , <linear-color-stop> ]#

<radial-extent> =
  closest-corner   |
  closest-side     |
  farthest-corner  |
  farthest-side

<length-percentage> =
  <length>      |
  <percentage>

<linear-color-stop> =
  <color> <length-percentage>?

<linear-color-hint> =
  <length-percentage>

```

示例
--

### 简单的渐变
```

<div class="radial-gradient"></div>
```

```
.radial-gradient {
  width: 240px;
  height: 120px;
}
```

```css
.radial-gradient {
  background-image: radial-gradient(cyan 0%, transparent 20%, salmon 40%);
}
```

### 非居中渐变
```

<div class="radial-gradient"></div>
```

```
.radial-gradient {
  width: 240px;
  height: 120px;
}
```

```css
.radial-gradient {
  background-image: radial-gradient(
    farthest-corner at 40px 40px,
    #f35 0%,
    #43e 100%
  );
}
```

### 更多径向渐变示例

请参见 CSS 渐变获取更多示例。

规范
--

| Specification |
| --- |
| CSS Images Module Level 3 # radial-gradients |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

参见
--

* 使用 CSS 渐变
* 其他的渐变函数：`repeating-radial-gradient()` (en-US)、`linear-gradient()` (en-US)、`repeating-linear-gradient()` (en-US)、`conic-gradient()` (en-US)、`repeating-conic-gradient()` (en-US)
* `<image>`
* `image()` (en-US)
* `element()`
* `image-set()` (en-US)
* `cross-fade()` (en-US)