CSS Grid:图文介绍
介绍
1. 开始之前
2. CSS网格基本属性
3. 高级模板
4. 隐式行和网格流
结论
这篇文章是两部分系列文章中的第一部分。
介绍
我还记得第一次学习 CSS 时的兴奋,当时我迫不及待地想学习浮动和内联显示,以便将元素按所需的布局放置。我当时很好奇,如果当时有一套二维布局系统,我会作何反应。实际上,即使是现在,我仍然对此感到兴奋,因为它改变了一切:不仅改变了我们编写 CSS 的方式,也改变了我们编写标记的方式。有了 CSS 网格,构建响应式、动态且不受源码顺序影响的布局比以往任何时候都更加容易。
在本文中,我们将学习所有 CSS 网格属性,以构建简单布局和一些不太简单的布局。我们将对所有内容进行定义,然后深入探究 CSS 网格可以实现哪些功能。
话虽如此,如果您准备好学习一种新的布局思维方式,那就吞下红色药丸吧,我将带您探索这个兔子洞的深度。

1. 开始之前
但在开始之前,我想解决您可能存在的一些问题,并确保我们熟悉 CSS 网格及其术语的基础知识。
问答
CSS 网格会取代弹性框吗?
其实,CSS 网格并不能取代 flex-box。它们是两种不同的工具,用于不同的目的。实际上,它们可以很好地协同工作,我们可以在网格显示内使用 flex 显示,反之亦然。
CSS 网格和弹性框之间有什么区别?
它们之间有很多区别,但最主要的一点是 flex-box 是一个一维布局系统,而 CSS grid 是一个二维布局系统。请看下面的图 1.1:
为什么不使用 bootstrap 来代替呢?
我认为这个问题的最佳答案是 Jen Simmons 的这句话:
我使用 CSS Grid 越多,就越确信在其上添加一层抽象层没有任何好处。CSS Grid 是嵌入浏览器的布局框架。—— Jen Simmons
CSS 网格是否已准备好投入生产?
视情况而定。您需要支持:IE、Opera mini、黑莓浏览器还是百度移动?如果答案是否定的,那么它已经可以投入生产了;如果答案是肯定的,那么在支持它的浏览器(无前缀浏览器:91.61%)上,您可以使用@supports
CSS at 规则使用它:
@supports (display: grid) {
div {
display: grid;
}
}
基础知识
基本上,网格可以分解为两个元素:网格容器和网格项。
如图 1.2所示,网格容器是一组列和行。Arow
是两条连续的行线(水平线)之间的空间,acolumn
是两条连续的列线(垂直线)之间的空间。行可以称为轨道,列也可以称为轨道。因此,网格track
是两条平行网格线之间的空间。
每个轨道可以包含一个或多个网格单元。网格cell
是最小的网格单元,也是最基本的网格单元。它是四条相交网格线之间的空间。如果我们将多个网格单元组合在一起,就得到了一个网格area
。需要注意的是,网格区域必须是矩形,例如不能是T形网格区域。
网格线数从 1 开始,直到您显式或隐式定义的线数。最后一个网格线数可以表示为 -1,其前一个网格线数可以表示为 -2,依此类推。这在后面会用到。在图 1.2
中,列线数从 1 到 6(或从 -6 到 -1),行线数从 1 到 5(或从 -5 到 -1)。
explicit
如果您在 CSS 中明确设置了网格线的数量,则会考虑网格线的数量。implicit
如果由浏览器动态设置,也会考虑网格线的数量。
最后,网格单元之间可以用空格或间隙分隔。这些间隙称为gutters
,但我们通常将其称为gaps
:)。
2. CSS网格基本属性
好了,现在我们可以开始实现一些网格了。首先,我们将讨论网格容器的所有可用属性,然后再看看网格项的属性。
让我们考虑本节的以下模板:
<div class="grid-container">
<div class="grid-item">grid item 1</div>
<div class="grid-item">grid item 2</div>
<div class="grid-item">grid item 3</div>
<div class="grid-item">grid item 4</div>
<div class="grid-item">grid item 5</div>
<div class="grid-item">grid item 6</div>
<div class="grid-item">grid item 7</div>
<div class="grid-item">grid item 8</div>
<div class="grid-item">grid item 9</div>
</div>
网格容器
展示
CSS 网格是使用属性grid
值定义的display
。因此,要使用上面的模板定义网格,我们应该这样做:
.grid-container {
display: grid;
}
行和列
grid-template-rows
我们可以使用和属性定义网格上的列和行grid-template-columns
:
.grid-container {
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr auto 2fr;
}
或者我们可以使用grid-template
首先定义grid-template-rows
然后定义grid-template-columns
(以斜线分隔)的地方:
.grid-container {
grid-template: 1fr auto 2fr / 1fr 1fr 1fr 1fr;
}
顺便说一下,anfr
是一个分数单位,所以1fr
是可用空间的 1 部分。
重复功能
该repeat()
函数表示曲目列表的重复片段。
因此,我们可以像这样实现与上面相同的模板:
.grid-container {
grid-template: 1fr auto 2fr / repeat(4, 1fr);
}
阅读此处的文档以了解如何使用auto-fit
和auto-fill
动态添加曲目。
最小最大函数
CSS函数minmax()
定义了一个大于或等于 min 且小于或等于 max 的尺寸范围。
我们可以repeat()
像这样使用它:
.grid-container {
grid-template-columns: repeat(3, minmax(100px, 1fr));
}
差距
我们可以使用 在行线之间添加间隙row-gap
,我们可以使用 在列线之间执行相同操作column-gap
:
.grid-container {
row-gap: 5px;
column-gap: 10px;
}
或者我们可以使用gap
首先定义row-gap
然后定义的column-gap
:
.grid-container {
gap: 5px 10px;
}
如果行距与列距相同,则只能指定一个值。
网格项目
为了指定网格项在网格中的起始和终止位置,我们主要使用四个属性。让我们看看它们的定义。
定义
特性 | 定义 |
---|---|
grid-row-start |
grid-row-start CSS 属性通过提供一条线、一个跨度或什么都不提供(自动)来指定网格项在网格行内的起始位置 |
grid-row-end |
grid-row-end CSS 属性通过提供一条线、一个跨度或什么都不提供(自动)来指定网格项在网格行内的结束位置 |
grid-column-start |
grid-column-start CSS 属性通过提供一条线、一个跨度或什么都不提供(自动)来指定网格项在网格列内的起始位置 |
grid-column-end |
grid-column-end CSS 属性通过提供一条线、一个跨度或什么都不提供(自动)来指定网格项在网格列内的结束位置 |
或者我们可以使用这些属性的缩短版本:
特性 | 定义 |
---|---|
grid-row |
grid-row CSS 属性是 grid-row-start 和 grid-row-end 的简写属性,用于指定网格项在网格行内的大小和位置 |
grid-column |
grid-column CSS 属性是 grid-column-start 和 grid-column-end 的简写属性,用于指定网格项在网格列中的大小和位置 |
基本模板间距
那么,考虑到我们在本节开头的标记,假设我们希望第三个网格项占用 4 个单元格而不是 1 个单元格(我们希望它跨越两个网格列和两个网格行),就像图 1.3中那样。我们该怎么做呢?
我们可以这样实现:
// Grid container
.grid-container {
display: grid;
gap: 10px;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 1fr);
}
// Grid item (third)
.grid-container .grid-item:nth-child(3) {
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 3;
// or
grid-column: 1 / 3;
grid-row: 1 / 3;
// or
grid-column: 1 / span 2;
grid-row: 1 / span 2;
// or
grid-column: -5 / span 2; // because we have 4 columns
grid-row: -4 / span 2; // because we have 3 rows
}
请注意,图 1.3中第三个网格项实际上是第一个。这与 CSS 网格首次实现了源顺序独立性有关。稍后讨论 时会稍微讨论这一点
grid-auto-flow
。
如果您想试用并探索不同的解决方案,请单击此处。
3. 高级模板
还有更多高级属性可以帮助您根据需要调整模板。在本节中,我们将研究这些属性,并了解如何在 CSS 中使用它们。
对于本节,请考虑以下模板:
<div class="grid-container">
<div class="grid-item header">Header</div>
<div class="grid-item content">Content</div>
<div class="grid-item navbar">Navbar</div>
<div class="grid-item meta">Meta</div>
<div class="grid-item footer">Footer</div>
</div>
利用我们之前学到的知识,我们可以实现以下 CSS,使其看起来像一个基本的网站布局:
.grid-container {
grid-template: repeat(6, 1fr) / repeat(12, 1fr);// rows then columns
}
.grid-container .header {
grid-column: 1 / -1; grid-row: 1 / 2;
}
.grid-container .navbar {
grid-column: 1 / 2; grid-row: 2 / -1;
}
.grid-container .content {
grid-column: 2 / -1; grid-row: 2 / -2;
}
.grid-container .footer {
grid-column: 2 / -1; grid-row: -2 / -1;
}
.grid-container .meta {
grid-column: -3 / -1; grid-row: 2 / 4;
}
现在假设我们希望右侧的导航栏稍微宽一点。目前,它横跨一列线,我们希望它横跨两列线。为此,我们必须更改 的位置,.navbar
但也必须更改.content
和 的.footer
位置,因为目前.navbar
是从第一列线到第二列线,而 &.footer
是.content
从第二列线到最后一列线。
如果每次都要修改元素的位置,那会很繁琐。如果有一种方法可以让 CSS 网格自动帮我们完成这项工作,那就太好了。嗯,方法不止一种,但至少有两种。
命名行
第一个解决方案是为特定的线路命名,然后使用其别名而不是其编号来引用它。让我们尝试实现这一点。
.grid-container {
grid-template-rows: repeat(6, 1fr);
grid-template-columns: 1fr 1fr [content-start navbar-end] repeat(10, 1fr);
}
在上面的代码中,我们使用简单的括号命名了第三行,并在括号内添加了别名(一行代码可以有多个别名)。接下来,我们将修改前面提到的元素的 CSS:
.grid-container .navbar {
grid-column: 1 / navbar-end; grid-row: 2 / -1;
}
.grid-container .content {
grid-column: content-start / -1; grid-row: 2 / -2;
}
.grid-container .footer {
grid-column: content-start / -1; grid-row: -2 / -1;
}
尝试对此代码片段中的其他行(例如:header-row-end / content-row-start)执行相同操作。
元素模板区域
第二种解决方案是使用模板区域。CSSgrid-template-areas
属性指定命名的网格区域。此属性的 CSS 语法比较奇怪,但我们可以使用如下方式:
.grid-container {
grid-template-areas:
'h h h h h h h h h h h h'
'n n c c c c c c c c c c'
'n n c c c c c c c c c c'
'n n c c c c c c c c c c'
'n n c c c c c c c c c c'
'n n f f f f f f f f f f';
}
.grid-container .navbar {
grid-area: n;
}
.grid-container .content {
grid-area: c;
}
.grid-container .footer {
grid-area: f;
}
.grid-container .header {
grid-area: h;
}
.grid-container .meta {
grid-column: -3 / -1; grid-row: 2 / 4;
}
我们使用grid-template-areas
来定义网格容器区域,然后使用 将网格项放置在所需的区域中grid-area
。
提醒一下,所有区域都必须是矩形。
注意我们没有使用
grid-area
for.meta
element。这是因为目前还没有办法用这种方法来叠加元素。至少我目前还不知道。
您可以尝试一下,代码可以在这里找到。
4. 隐式行和网格流
让我们考虑以下代码:
<div class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
</div>
<style>
.grid-container {
grid-template-columns: repeat(3, minmax(100px, 1fr));
grid-template-rows: 80px;
}
.grid-container .grid-item:nth-child(2) {
grid-row: span 2;
}
.grid-container .grid-item:nth-child(3) {
grid-column: span 3;
}
</style>
我们有一个三列的网格,我们希望第二个网格项跨越两行,第三个网格项跨越三列。结果如下:
这看起来很糟糕,那么这里发生了什么?首先,第二个元素比第一个元素略高,因为我们设置它的高度是第一个元素的两倍,但它看起来根本没有高两倍。而且,从 3 到 6 的网格项比第一个元素的高度要低。
隐式行
这与我们显式设置第一行有关:grid-template-rows: 80px;
。但其他行是隐式创建的,所以第二行几乎不可见,因为它是空的,而其他行的大小已根据其内容需要而定。
我们可以通过如下方式设置隐式创建的行的高度来解决这个问题grid-auto-rows
:
.grid-container {
grid-template-columns: repeat(4, minmax(100px, 1fr));
grid-template-rows: 80px;
grid-auto-rows: 100px;
}
这样看起来好多了,但我们还可以做得更好。注意到那些空白处,我们为什么不使用它们来放置网格项 4、5 和 6 呢?
为此,我们可以使用grid-auto-flow
。
网格流
CSSgrid-auto-flow
属性控制自动放置算法的工作方式,指定自动放置的项目如何流入网格。它可以接受多个参数(您可以在此处阅读更多信息),但这里我们只关注一个:dense
。
这将告诉浏览器将项目放置在任何足够大的空间上:
.grid-container {
grid-auto-flow: dense; // default is row
}
这样我们的网格终于看起来漂亮了:)
结论
这些信息量很大,但我们已经了解了 CSS 网格的许多属性,所以你应该可以轻松地在应用中使用 CSS 网格了。这篇文章是系列文章的第一篇,下一篇我们将使用网格实现三个实际示例,敬请期待。
我希望您学到一些有用的东西,并一如既往地祝您编码愉快!
嘿,我们保持联系吧!
我正在创作很多精彩的文章和教程。如果你喜欢这篇,记得在Twitter上关注我,这样就能及时了解下一篇的发布时间。