zzxworld

学习 CSS Grid 网格布局

距离上次《学习 CSS Flex 弹性盒子布局已经过去了十来天,今天有了点时间,继续来了解另外一个更加厉害的 CSS 布局技术:Grid 网格布局。

和 Flex 弹性盒布局技术相比,Grid 网格布局的厉害之处在于它是「二维」的。这个「二维」的意思是 Grid 网格能从「行」和「列」两个维度来操控元素的位置空间,所以在处理复杂的显示结构时十分得心应手。我在学习并使用它的过程中甚至有了用 Table 布局时那种随心所欲的体验。

使用 grid 属性

使用 Grid 网格布局非常简单,只需要在容器标签元素上定义如下样式属性:

display: grid;

仅定义这个属性还不能让容器内的元素以网格方式显示,看起来也和默认显示样式没什么差别。这是因为还没设置网格列。

设置网格列

在网格容器标签上使用 grid-template-columns 属性可以设置网格列:

grid-template-columns: 200px 200px;

这样就定义了一个两列的网格布局。想定义几列就输入几次长度属性值。比如要定义 4 列:

grid-template-columns: 200px 200px 200px 200px;

每列的宽度也可以随意指定:

grid-template-columns: 200px 500px 100px;

使用 px 定义的列宽度是固定的,这不能满足适配各种大小屏幕显示的需求。所以还有另一种更加舒服的定义方式:

grid-template-columns: 1fr 1fr;

同样是定义了两列的网格布局,但这次列的宽度会自动适配屏幕宽度。fr 是网格布局的专用长度单位,它会通过容器标签的可用空间自动计算列的显示大小。

pxfr 也可以混用,这样可以实现一列固定,一列自动伸缩的布局效果:

grid-template-columns: 200px 1fr;

设置间距

使用网格布局时,在列和行之间使用间距是很常见的需求。之前在用浮动定位布局时这方面处理起来就很麻烦。要么需要提前计算好元素大小和间距大小,要么用额外的围栏标签。使用 Grid 布局就简单多了,只需要在容器元素上使用一个属性:

gap: 10px;

使用 repeat 函数

上面在使用 grid-template-columns 定义列时说道,需要几列就在属性值部分重复几次长度值。这在列多了后会略微显得比较麻烦。遇到这种情况,就可以使用 repeat 函数了:

grid-template-columns: repeat(12, 1fr);

这样就轻松定义了一个 12 列的网格布局。

使用 minmax 函数

上面使用 grid-template-columns 属性定义的列数量都是固定的。假设现在有一个需求是列的宽度要保持一个最小值,但在更宽的屏幕上可以自动安排合适的列宽以及列数量时该如何实现呢?也许你会想到使用 CSS 的 Media Query 功能。但在此之前,可以先试试 minmax 函数:

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

上面会让每个列至少保持 300px 的长度,当有更多空间时,会自动扩展列的长度和可以显示的列数。

自定义网格位置

这是 Grid 网格布局最灵活的布局功能了。在使用这个功能前,我建议在火狐浏览器上先打开浏览器的开发者工具。然后点开「检查器」功能。

firefox inspector

在定义了 Grid 属性的容器元素后面,会出现 grid 提示,点击这个提示。然后在旁边的网格设置中,勾选「显示行号」设置。这时会发现页面中出现了一些线框和带数字的提示:

Screenshot Grid Test

自定义网格位置就和这些线框和数字有关了。比如我要在上面这个三列布局的网格中,让第一个网格元素占用两列显示,就只需要在第一个网格元素中使用这样一行 CSS 代码:

grid-column: 1 / 3;

属性值 1 和 3 分别为上面 Grid 提示线框中编号为 1 和 3 的竖线,代表了自定义网格元素的列起始位置。来看看效果:

Screenshot Grid Test 1

可以看到第一个元素占据了两列网格空间。

使用 grid-row 还可以定义行网格空间:

grid-row: 1 / 3;

这时的属性值要参考提示框中的横线编号。来看看显示效果:

Screenshot Grid Test 2

把这个两个属性组合起来用,还可以把第一个元素定位到网格中间显示:

grid-column: 2 / 3;
grid-row: 3 / 4;

下面是显示效果:

Screenshot Grid Test 3

我已经想不出还有比这更灵活的 CSS 布局方式了。