CSS 网格为我们提供了强大的网站布局系统。 CSS-Tricks 指南 为您全面概述了网格属性及其布局示例。 我们将在这里采用一种逆向方法,向您展示满足大多数布局需求所需的最小的网格属性集。
这五个属性将助您快速入门
display
(用于grid
值)grid-template-columns
grid-gap
grid-auto-flow
grid-column
/grid-row
这真的很简单。 假设您想为小型、中型和大型屏幕实现以下布局。


这是我们将要使用的标记
<!-- Stuff before -->
<nav class="container-nav">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</nav>
<div class="container-main">
<section class="item item-type-a"></section>
<section class="item item-type-b"></section>
<section class="item item-type-b"></section>
<section class="item container-inner">
<section class="item-inner"></section>
<section class="item-inner"></section>
<section class="item-inner"></section>
<section class="item-inner"></section>
<section class="item-inner"></section>
</section>
</div>
<!-- Stuff after -->
如果我们应用一些基本样式,就会得到以下结果,这对于小型屏幕来说已经足够了
现在我们可以开始使用网格属性了!
使用 display: grid 将页面划分为独立的布局容器
首先,我们需要确定页面中哪些部分应该与网格布局对齐。 可以为整个页面定义单个网格布局。 但是,对于结构非常复杂的网站(例如新闻网站),处理大型网格很快就会变得难以驾驭。 在这种情况下,我建议将页面分解成几个独立的网格容器。
像这样

您如何在什么应该是什么不应该成为网格之间划清界限? 这里有一个我遵循的个人经验法则
如果页面特定部分的布局不适合相邻或周围部分的网格,则将该部分设置为自己的网格容器。
我在以下图片中用网格线绘制了带有类 .container-main
的页面部分。 您可能会注意到,标记中的带有 .container-inner
类的部分不完全适合网格行。

这是一个可能的布局,其中如果选择更细的线栅格,则小部分将适合周围的网格。 在这里,单独的网格容器不是绝对必要的。

要开始,让我们将 .container-main
设置为网格容器。 这是 CSS 网格的基本构建块 - 使用 display
属性将元素转换为网格容器
.container-main {
display: grid;
}
我们也希望对其他网格容器执行相同的操作
.container-inner {
display: grid;
}
.container-nav {
display: grid;
}
使用 grid-template-columns 定义所需的列
接下来,我们将定义每个网格容器中所需的列数以及这些列的宽度。 我对列数的准则: 使用不同屏幕尺寸所需的最大列数的最小公倍数。
它是如何工作的? .container-main
元素在中型屏幕上总共有两列。 如果我们将其乘以大型屏幕上的列数(三列),我们将得到总共六列。
我们可以对导航 .container-inner
元素执行相同的操作。 在中型屏幕上,有三个列,我们将其乘以大型屏幕上的一个列,得到总共三个列。
.container-nav
元素没有提供任何列数。 在这种情况下,网格系统应自动将列数调整为菜单元素的数量。 通常会在导航中添加或删除项目,如果它能相应地做出响应将非常好,这是网格稍后可以帮助我们实现的功能。
好的,因此我们为每个网格容器定义了列数。 让我们使用 grid-template-columns
属性将它们设置到位。 但是,首先要考虑几个细节
grid-template-columns
属性仅在网格容器上使用。 换句话说,您不会在容器内的网格项上找到它(至少不会使用正确的方式)。- 该属性接受许多不同的值,这些值同时定义了列数及其宽度。 我们这里感兴趣的是分数 (
fr
) 单位。 我强烈建议查看 Robin 的概述,因为它在网格中是独一无二的,并且在确定网格元素如何适合网格容器方面做得非常出色。
我们需要在 .container-main
中创建六个等宽列。 我们可以这样写
.container-main {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
}
或者,我们可以转向 repeat()
函数将其简化为更易读的内容
.container-main {
display: grid;
grid-template-columns: repeat(6, 1fr);
}
让我们利用这些知识也应用于 .container-inner
元素,我们决定它需要三列。
.container-inner {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
使用 grid-gap 在网格项之间添加间距
默认情况下,网格会使用网格容器中的所有空间来容纳网格项。 使元素紧密相邻可能是设计要求,但不适用于我们正在制作的特定布局。 我们希望在元素之间留出一些空间!
我们有 grid-gap
属性来实现这一点。 同样,这只是一个网格容器的属性,它的作用是在网格项之间创建垂直和水平间距。 它实际上是一个简写属性,它结合了 grid-row-gap
的垂直间距功能和 grid-column-gap
的水平间距功能。 能够将它们分解成这样很方便,但在像这样我们在每个方向上都使用相同间距的情况下,简写 grid-gap
编写起来更方便。
我们希望在 .container-main
中的网格项之间留出 20px
的空间,在 .container-inner
中留出 10px
的空间,在 .container-nav
中留出 5px
的空间。 没问题! 只需在每个网格容器上添加一行代码即可。
.container-main{
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-gap: 20px;
}
.container-inner {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 10px;
}
.container-nav {
display: grid;
grid-gap: 5px;
}
使用 grid-column 和 grid-row 确定单个网格项的大小
现在是时候将布局塑造成我们想要的样子了!
首先是 grid-column
属性,它允许我们将网格项扩展到 n 列,其中 n 是要跨越的列数。 如果您认为这听起来非常类似于 rowspan
属性,它允许我们将单元格扩展到 HTML 表格中的多行,那么您是对的。
当我们在 .container-main
元素中的网格 .item
上使用它时,以及在 .container-inner
中的 .inner-item
元素上使用它时,它看起来像这样
.item {
grid-column: span 6;
}
.item-inner {
grid-column: span 3;
}
我们在这里表示,每个项目在我们主容器中跨越六行,在我们内部容器中跨越三行 - 这相当于每个容器中的总列数。
CSS 网格的一个有趣之处在于,我们能够对网格线进行命名。 它们自带隐式名称,但为它们命名是一种强大的方法,可以区分每个列上的轨道上的起始线和结束线。
我们可以在不同的断点更改项目应跨越的列数和行数
@media screen and (min-width: 600px) {
.item-type-b {
grid-column: span 3;
}
.item-inner {
grid-column: span 1;
}
}
@media screen and (min-width: 900px) {
.item {
grid-column: span 2;
grid-row: span 2;
}
.item-type-b{
grid-row: span 1;
}
.item-inner{
grid-column: span 3;
}
}
使用 grid-auto-flow 控制元素的放置
CSS 网格会按顺序将元素放置在一行一行中。 这就是为什么我们示例中的结果目前看起来像这样

可以通过将 grid-auto-flow
属性设置为列 (row
是默认值) 来实现逐列放置。 我们的布局将在两种情况下受益于按列放置。 首先,它使我们的菜单项最终以水平方向显示。 其次,它将容器类元素带入所需的组合中。
最终结果
结论:多少规范?
网格系统允许我们在“尽可能少地制定必要规范”的口号下工作。为了仅展示构建复杂布局所需的知识量很少,我们只介绍了将元素转换为 CSS 网格容器以及将其中元素转换为网格项目的必要规范中的几个。
CSS 网格支持更多用例,例如:
- 我们希望制定更少的规范,以便更多地依赖自动定位。
- 我们希望制定更多规范,以便确定结果布局的更多细节。
如果第一个案例适用,那么值得考虑以下附加网格选项:
- 使用 `grid-template-columns` 创建网格时,您可以使用 `auto` 关键字让网格系统自动确定各个列的宽度,或者使用 `min-content`、`max-content` 或 `fit-content` 设置使其适应现有内容。
- 您可以借助 `repeat`、`auto-fill`、`auto-fit` 和 `minmax` 让网格系统自动确定所需列数。甚至媒体查询也可以变得冗余,这些工具有助于在不添加更多媒体查询的情况下使布局灵活。
以下是我推荐的一些关于此主题的文章:成为 CSS 网格忍者! 和 CSS 网格中的自动调整列宽:auto-fill vs. auto-fit.
如果第二个案例适用,CSS 网格为您提供了更多设置选项:
- 您可以使用 `grid-template-columns` 属性显式指定列的宽度,以您选择的单位(例如 `px` 或 `%`)。此外,还可以使用 `grid-template-rows` 属性来定义行数和宽度,如果存在特定行数的话。
- 您还可以为 `grid-column` 和 `grid-row` 定义特定列或行号作为定位值(或者使用 `grid-column-start`、`grid-column-end`、`grid-row-start` 或 `grid-row-end` 属性)。
我们甚至还没有谈到 CSS 网格对齐!不过,即使没有触及该主题,我们也能实现如此多的功能,这表明 CSS 网格功能多么强大。
文章写得很好!已将其添加书签,以便将来参考!
只是想指出,`grid-gap`、`grid-column-gap` 和 `grid-row-gap` 实际上已弃用,应使用 `gap`、`column-gap` 和 `row-gap`。
https://mdn.org.cn/en-US/docs/Web/CSS/gap
哇,弃用?太疯狂了。不过,我敢打赌浏览器永远不会移除对它的支持。现在已经太普遍了。
在 flexbox 示例中看到 `gap` 的使用很有趣。我假设这意味着它可以与两种 `display` 值一起使用。
所有 `gap` 属性现在都在盒子对齐规范中定义。这意味着它们可以应用于任何有意义的布局方法。
弃用的 `grid-` 前缀属性也在其中介绍:https://www.w3.org/TR/css-align-3/#gap-legacy
现在没有理由使用带前缀的属性,因为所有浏览器都支持无前缀版本,但是如果您有使用它们的网站,它们不会消失并导致问题。
我仍然不明白为什么没有更多地关注 `grid-template-areas`。如果您想谈论网格带来的最大好处,它实际上是能够在您的 CSS 中直观地模拟布局!
以下是不使用媒体查询的解决方案:https://codepen.io/dannievinther/pen/GRJeqVv
适用于 Firefox 75+(Nightly)和 Chrome
有理由偏好非媒体查询解决方案吗?
@Max.
不一定。但是,如果您选择将各种元素视为独立的(灵活的)组件,可能会有一些好处。组件进入的上下文并不总是严格定义的,因此,通过在组件本身中写入指令(可以这么说),您在一定程度上确保了它无论上下文如何都适合任何上下文。设置媒体查询规则没有那么灵活,它们完全基于视窗——组件不一定基于视窗。
使用不需要媒体查询的技术可以提高元素布局的灵活性,而无需显式定义它们。
也就是说,这将取决于您的工作流程和/或上下文!
我在这篇文章中写了一篇关于这个主题的文章:https://blog.logrocket.com/flexible-layouts-without-media-queries/
我非常喜欢 CSS 网格,并在很多项目中使用它——但是对我来说,一个很大的缺点是 IE 支持不好。例如,`autofill` 在 IE11 中不起作用,因此作为备用方案,我需要使用 `grid-template-columns/columns` 设置每个子元素的位置。因为我仍然必须在我的所有项目中支持 IE11。我太厌倦 IE 了!
很棒的内容,CSS 网格是一个游戏规则改变者。我将很乐意用它来布局一些旧插件(并简化大多数 HTML 生成器)。