网格布局的基本概念
CSS 网格布局 将二维网格系统引入 CSS。网格可用于布局主要页面区域或小型用户界面元素。本文介绍了 CSS 网格布局以及 CSS 网格布局级别 1 规范中包含的新术语。本概述中显示的功能将在本指南的其余部分中进行更详细的解释。
什么是网格?
网格是一组相交的水平线和垂直线,定义了列和行。元素可以放置在这些列和行线内的网格上。CSS 网格布局具有以下功能
固定和灵活的轨道大小
您可以使用固定轨道大小创建网格,例如使用像素。这将网格设置为指定的像素,以适应您所需的布局。您还可以使用百分比或专为此目的设计的 fr
单位创建使用灵活大小的网格。
项目放置
您可以使用行号、名称或通过定位网格的某个区域将项目放置到网格上的精确位置。网格还包含一个算法来控制未在网格上指定显式位置的项目的放置。
创建额外的轨道来容纳内容
您可以使用网格布局定义显式网格。网格布局规范足够灵活,可以在需要时添加额外的行和列。其中包括添加“尽可能多地适合容器的列”等功能。
对齐控制
网格包含对齐功能,因此我们可以控制项目放置到网格区域后如何对齐,以及整个网格如何对齐。
重叠内容的控制
网格容器
我们通过在元素上声明 display: grid
或 display: 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 开发者工具中提供的 网格检查器 会很有帮助。如果您在 Firefox 中查看此示例并检查网格,您将在值 grid
旁边看到一个小图标。单击它,然后网格将覆盖在浏览器窗口中。
在您学习并使用 CSS 网格布局时,此工具将让您更好地了解网格的视觉效果。
如果我们想让它更像网格,我们需要添加列轨道。
网格轨道
我们使用 grid-template-rows
和 grid-template-columns
属性在网格上定义行和列。这些定义了网格轨道。网格轨道是网格上任意两条相邻线之间的空间。下图显示了一个突出显示的轨道——这是我们网格中的第一行轨道。
网格轨道在显式网格中使用 grid-template-columns
和 grid-template-rows
属性或简写 grid
或 grid-template
属性定义。网格轨道也在隐式网格中创建,方法是将网格项目放置在显式网格中创建的轨道之外。
基本示例
我可以通过添加 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 单位
可以使用任何长度单位定义轨道。网格还引入了额外的长度单位来帮助我们创建灵活的网格轨道。新的 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
轨道。可用空间被分成四部分。两部分分配给第一条轨道,其余两部分分别分配给接下来的两条轨道。
<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: 2fr 1fr 1fr;
}
混合灵活和绝对尺寸
在此最后一个示例中,我们将绝对尺寸轨道与 fr
单位混合使用。第一条轨道为 500 像素,因此固定宽度将从可用空间中减去。剩余的空间将分成三部分,并根据两条灵活轨道的比例分配。
<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: 500px 1fr 2fr;
}
使用 repeat() 表示法的轨道列表
包含许多轨道的较大网格可以使用 repeat()
表示法来重复所有或一部分轨道列表。例如,网格定义
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
也可以写成
.wrapper {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
重复表示法可用于轨道列表的一部分。在下一个示例中,我创建了一个网格,它包含一个初始的 20 像素轨道,然后是 6 个 1fr
轨道的重复部分,最后是一个 20 像素轨道。
.wrapper {
display: grid;
grid-template-columns: 20px repeat(6, 1fr) 20px;
}
重复表示法采用轨道列表,并使用它创建重复的轨道模式。在此下一个示例中,我的网格将包含 10 个轨道,一个 1fr
轨道,然后是一个 2fr
轨道。此模式将重复五次。
.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()
函数。在此下一个示例中,我在 grid-auto-rows
的值中使用 minmax()
。这意味着自动创建的行将至少为 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>
网格线
需要注意的是,当我们定义网格时,我们定义的是网格轨道,而不是线条。然后,网格为我们提供了编号的线条,以便在放置项目时使用。在我们的三列两行网格中,我们有四条列线。
线条的编号根据文档的书写模式进行。在从左到右的语言中,第 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 开发者工具中使用 网格检查器 来查看项目是如何相对于网格线条定位的。
线条定位简写
上面使用的完整值可以使用 grid-column
压缩到列的一行,并使用 grid-row
压缩到行的一行。以下示例将提供与之前代码相同的定位,但 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;
}
网格单元格
网格单元格是网格上最小的单元。从概念上讲,它类似于表格单元格。正如我们在之前的示例中看到的,一旦网格被定义为父元素,子项目将分别在一个定义的网格单元格中进行布局。在下图中,我突出显示了网格的第一个单元格。
网格区域
项目可以通过行或列跨越一个或多个单元格,这将创建一个网格区域。网格区域必须是矩形的——例如,无法创建 L 形区域。突出显示的网格区域跨越了两行和两列轨道。
间隙
可以使用 column-gap
和 row-gap
属性或简写 gap
创建网格单元格之间的间隙或巷道。在下面的示例中,我在列之间创建了 10 像素的间隙,在行之间创建了 1em
的间隙。
.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
。
所有浏览器现在都支持无前缀的值,但是前缀版本将作为别名保留,因此可以安全地使用。
<div class="wrapper">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
间隙使用的任何空间将在将空间分配给灵活长度 fr
轨道之前进行计算,并且间隙在大小调整方面就像常规网格轨道一样,但是您不能将任何内容放置到间隙中。在基于线条的定位方面,间隙就像一条粗线。
嵌套网格
网格项目可以成为网格容器。在以下示例中,我创建了之前创建的三列网格,其中包含我们放置的两个项目。在本例中,第一个项目有一些子项目。由于这些项目不是网格的直接子元素,因此它们不参与网格布局,因此以正常的文档流显示。
不使用子网格嵌套
如果我将 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);
}
<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>
* {
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
,并且嵌套网格中的线条与父网格中的线条不对齐。
子网格
除了常规网格之外,子网格允许我们创建使用父网格的轨道定义的嵌套网格。
要使用它们,我们将编辑上面的嵌套网格示例,将 grid-template-columns: repeat(3, 1fr)
的轨道定义更改为 grid-template-columns: subgrid
。然后,嵌套网格使用父网格轨道来布局项目。
.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 重叠
如果我们回到使用行号定位项目的示例,我们可以更改它以使两个项目重叠。
<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
,它将显示在 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;
}
后续步骤
在本文中,我们快速了解了网格布局的可能性。探索和玩弄代码示例,然后继续 本指南的下一部分,在那里我们将真正开始深入探讨 CSS 网格布局的细节。