MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

翻译正在进行中。

CSS网格布局引入了二维网格布局系统,可用于布局页面主要的区域布局或小型组件。本文介绍了CSS网格布局 与 CSS网格布局规范 Level 1 中的新术语。这篇简介中所展示的每种特性,随后将在本指南的其余部分中有更详细地介绍。

什么是网格?

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

固定或弹性的轨道尺寸

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

定位项目

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

创建额外的轨道来保存内容

可以使用网格布局定义一个显式网格,但该规范还涉及在声明网格外添加的内容,如需要添加额外的行和列。包括添加“尽可能多的列,以适应容器”的功能。

对齐控制

网格包含对齐特征,以便我们可以控制一旦放置到网格区域中的物体对齐,以及整个网格如何对齐。

控制重叠内容

多个项目可以放置在网格单元格中,或者区域可以部分地彼此重叠。然后可以用这种分层进行控制z-index

Grid是一个强大的规范,当与CSS的其他部分(如flexbox)结合使用时,可以帮助您创建以前不可能在CSS中构建的布局。这一切都是通过在网格容器上创建一个网格来开始的。

网格容器

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

在这个例子中,我有一个类名为 wrapper 的作为容器的 div 元素,它内部有五个子元素。

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

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

.wrapper {
  display: grid;
}

所有直系子元素现在都是网格项目了。在网络浏览器中,当网格为项目创建单列列网格时,在将项目显示为网格之前,您将看不到任何差异。在这一点上,你可能会发现在Firefox Developer Edition中有用,该开发人员版具有Grid Inspector作为开发工具的一部分。如果你在Firefox中查看此示例并检查网格,则会在值网格旁边看到一个小图标。单击此处,此元素上的网格将覆盖在浏览器窗口中。

Using the Grid Highlighter in DevTools to view a grid

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

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

网格轨道

我们通过定义网格容器的grid-template-columns和grid-template-rows属性来定义网格中的行和列。这些属性定义了网格的轨道。一个网格轨道就是网格中任意两条线之间的空间。在下图中你可以看到一个高亮的轨道-网格的第一个行轨道。

我可以通过添加grid-template-columns属性添加到我们前面的例子,然后定义列轨迹的大小。

我现在创建了一个网格,三个200像素宽栏轨道。子项目将在每个网格单元中的网格上展开。

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>
.wrapper {
  display: grid;
  grid-template-columns: 200px 200px 200px;
}

fr单位

轨道可以使用任何长度单位进行定义。 Grid还引入了一个额外的长度单位来帮助我们创建灵活的网格轨道。新的fr单位代表网格容器中可用空间的一等份。下一个网格定义将创建三个相等宽度的轨道,这些轨道会随着可用空间增长和收缩。

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>
.wrapper {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}

在下面的这个例子中,我们创建定义了一个2fr轨道和两个1fr轨道。可用空间分割为四。两份给了第一个轨道,剩下两个轨道各一份。

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

在最后这个例子中,我们混合了绝对尺寸的轨道与分数单位轨道。第一个轨道是500像素,这个固定宽度被从可用空间中取走。剩下的空间被分为三份,按比例分配给了两个弹性尺寸轨道。

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

在轨道清单中使用repeat()

具有许多轨道的大网格可以使用repeat()语句表示重复一部分或者整个轨道清单。例如网格定义:

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

也可以写成:

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

Repeat语句可以被用作轨道清单中的一部分。在下一个例子中我创建了一个网格:它起始轨道为20像素,接着用repeat声明了6个1fr的轨道,然后再添加了一个20像素的轨道。

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

Repeat语句可以接受一个轨道清单,因此你可以用它来创建一个按多个轨道作为模式的重复的轨道清单。在下一个例子中,网格将会包括10个轨道,1个1fr的轨道后面跟着1个2fr的轨道,重复5次。

.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像素高。

<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>
.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px;
}

轨道大小和minmax()

在设置一个显式的网格或者定义自动创建的行和列的大小的时候,我们也许想给网格一个最小的尺寸,但要确保他们能扩大到容纳他里面添加的内容。举个例子,我想让我的行的高度永远不会缩小到100像素以下,但是如果我的内容延伸到300像素高了我想让我的行高也延伸到这个高度。

网格用minmax()函数来解决这个问题。在下一个例子中我用minmax()作为grid-auto-rows的值。自动创建的行高将会是最小100像素,最大为auto。用auto意味着行的尺寸将会根据内容的大小来自动变换:根据本行中最高的单元,把空间扩展到足够容纳该单元。

.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: minmax(100px, auto);
}
<div class="wrapper">
   <div>One</div>
   <div>Two
   <p>I have some more content in.</p>

<p>This makes me taller than 100 pixels.</p>
</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>

网格线

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

Diagram showing numbered grid lines.

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

跨轨道放置网格项目

我们会在以后的文章中完整的探讨如何根据 网格线 定位元素,接下来的例子展示了一个简单的方法。当放置元素时,我们使用 网格线 定位,而非 网格轨道。

接下来这个例子中,我使用了grid-column-start, grid-column-end, grid-row-start 和 grid-row-end 属性,把前两个元素放到了我们的三列网格中。从左至右,第一个元素从列线1开始,延伸至列线4,也就是我们这个例子中最右边的列线。并从行线1延伸到行线3,占据了两个行轨道。

第二个元素从列线1开始,延伸了一个轨道。因为这是默认行为,所以我不用指定结束线。并且它从行线3到行线5,跨越了两个行轨道。剩下的元素会把自己安放到网格空余的空间中。

<div class="wrapper">
   <div class="box1">One</div>
   <div class="box2">Two</div>
   <div class="box3">Three</div>
   <div class="box4">Four</div>
   <div class="box5">Five</div>
</div>
.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; 
}

别忘了你可用火狐开发者工具(Firefox Developer Tools)中的网格检视器( Grid Inspector )查看这些元素是如何被摆放在网格中的。

网格单元

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

The first cell of the grid highlighted

网格区域

网格项目可以向行或着列的方向扩展一个或多个单元,并且会创建一个网格区域。网格区域的形状应该是一个矩形 - 也就是说你不可能创建出一个类似于“L”形的网格区域。下图高亮的网格区域扩展了2列以及2行。

A grid area

网格间距

在两个网格单元之间的 网格横向间距  或 网格纵向间距  可使用 grid-column-gapgrid-row-gap 属性来创建,或者直接使用两个合并的缩写形式 grid-gap。在下面的例子中,我会创建一个横向间距为10px、纵向间距为1em的网格元素。

.wrapper {
   display: grid;
   grid-template-columns: repeat(3, 1fr);
   grid-column-gap: 10px;
   grid-row-gap: 1em;
}
<div class="wrapper">
   <div>One</div>
   <div>Two</div>
   <div>Three</div>
   <div>Four</div>
   <div>Five</div>
</div>

Any space used by gaps will be accounted for before space is assigned to flexible length fr tracks, and gaps act for sizing purposes like a regular grid track, however you cannot place anything into a gap.

间距使用的空间会在 使用弹性长度fr的轨道的空间 计算前就被留出来,间距的尺寸定义行为和普通轨道一致,但不同的是你不能向其中插入任何内容。从以基线定位的角度来说,间距就像一条很宽的基线。

嵌套网格

一个网格项目可以也成为一个网格容器。在接下来的例子中我事先有了一个3列的网格元素,并有两个跨轨道的网格。在这个例子中,第一个网格项目含有几个子级项目。当这些项目不是网格容器的直接子级元素时,它们不会参与到网格布局中,并显示为正常的文档流。

<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">Two</div>
    <div class="box box3">Three</div>
    <div class="box box4">Four</div>
    <div class="box box5">Five</div>
</div>

Nested grid in flow

如果我把 box1 设置成 display: grid 我可以给它定义轨道然后它也会变成一个网格元素,它的子级元素也会排列在这个新网格元素中。

.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);
}

在这个例子中,嵌套网格和他的父级并没有关系。就像你在例子中所看见的一样,它并没有从它的父级继承 grid-gap 属性,并且嵌套网格里面的网格线没有与父级的网格线对齐。

子网格

在Level 1网格规范中有一个叫做 子网格  的特性。它能让我们在父级网格元素的轨道定义中就能定义一个嵌套网格。

子网格还并未在任何浏览器中实现,并且随时有可能从规范中移除。

在当前的规范中,我们我们可以将上面的嵌套网格的例子进行修改,使用 display: subgrid 而不是 display: grid,然后移除轨道定义。嵌套网格将会使用父级网格元素中的轨道定义来排列它其中的网格项目。

需要指出的是嵌套网格有同时有两个单位 — 行和列。隐式子网格的概念是没有的,这意味着你需要确保父级网格元素为了许哦有的子网格项目需要包含足够的行与列的轨道。

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

使用z-index控制层级

多个网格项目可以占用同一个网格单位。如果我问回到之前根据网格线编号放置网格项目的话,我们可以更改此项来使两个网格项目重叠。

<div class="wrapper">
   <div class="box box1">One</div>
   <div class="box box2">Two</div>
   <div class="box box3">Three</div>
   <div class="box box4">Four</div>
   <div class="box box5">Five</div>
</div>
.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;
}

网格项目 box2 现在覆盖于 box1 之上,其覆盖顺序遵循文档流的原始顺序(后来居上)。

控制顺序

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

.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;
}

下一步

在本文章中我们快速对网格布局的概念有了个基本的了解。利用示例代码进行练习,然后接下来我们正式开始挖掘关于网格布局的各种细节

文档标签和贡献者

标签: 
 此页面的贡献者: fskuok, zsxeee, lipd, EzioW, 1986slayer
 最后编辑者: fskuok,