CSS 教程 / CSS Grid 基础:轨道、网格线与项目放置
CSS 网格为二维布局定义行和列,并将直接子项目放入该网格中。网格线界定轨道和单元格;一个项目可以跨越多个轨道而不改变文档顺序。
识别容器、线条、轨道、单元格和区域
网格容器是应用了 display: grid 的父容器,网格项是该父容器的直接子元素。第一子元素内部的子元素在外层网格中不是独立的项。在 CSS 中绘制网格不会创建新的 HTML 元素;它只是改变了我们计算每个子元素在网格中位置的方式。
| 术语 | 含义 | 2 列 2 行的示例 |
|---|---|---|
| 网格线 | 划分行和列的边界 | 3 条垂直线,3 条水平线 |
| 轨道 | 两条相邻网格线之间的一行或一列 | 第一列,第二行 |
| 单元格 | 一行一列交汇的最小区域 | 左上角的一个空格 |
| 区域 | 由一个或多个单元格组成的矩形 | 跨两列的标题区域 |
网格线编号与列编号不同。两列连同外边界共有三条垂直网格线,编号为 1、2、3。项目从第 1 条线延伸至第 3 条线时,覆盖的是两列。gap 是轨道之间的间隙,单独计算,不包括项目的内边距或边框。通过在开发者工具的元素中打开网格显示,可以查看网格线编号和实际区域。MDN:Grid 基本概念 总结了术语和基本操作。
用 px、百分比和 fr 定义列
.grid {
display: grid;
grid-template-columns: 160px 1fr;
gap: 16px;
}
此部分代码可以通过替换完整示例中 .grid 规则中的列声明来进行比较。第一列使用 160px,第二列使用剩余空间。fr 表示可用空间的一份,在考虑其他轨道与 gap 后按比例分配剩余空间。在不考虑内容的情况下冻结第一列可能会使窄屏设备上的主体区域过窄,因此应根据实际内容来判断。
在宽度为 640px 的容器中,如果间隙为 16px 且两列为 1fr·2fr,则需要分配的空间为 624px。如果没有最小尺寸约束,第一列为 208px,第二列为 416px。完整示例使用 minmax(0, 1fr) minmax(0, 2fr) 将轨道的最小尺寸明确设为 0,避免长内容通过自动最小尺寸撑宽轨道。
如果你同时使用 50% 50% 和 gap: 16px,容器的宽度可能已经仅由列填满,然后间距可能会导致溢出。对于需要弹性分配空间的列,fr 更便于计算。这并不意味着你需要让所有列的比例相同。你的列表可能需要一个小的名称列和一个大的描述列,你也可能希望使用固定列和弹性列的组合。
比较显式行和隐式行
grid-template-rows: 80px 明确定义了第一行。如果没有足够的行来放置后面的项目,将会创建一个隐式行,其大小可以通过 grid-auto-rows 调整。创建两列并不限制你只能有两行。
| 行高 | 行为 | 需要注意的情况 |
|---|---|---|
| auto | 尺寸根据内容和容器的空间及对齐条件确定。 | 在固定高度的容器中,可能会反映出剩余空间 |
| 100px | 固定行高 | 内容过长时可能溢出固定行高。 |
| minmax(100px, auto) | 确保至少100px,如有必要可更大 | 适用于内容可扩展的卡片 |
在存在明确尺寸要求时使用固定行,但让说明卡片容纳翻译或放大文本产生的额外行。minmax(100px, auto) 设置了最小值并允许增长;它不要求所有行具有相同的高度。每行取决于其内容和布局条件。显式行之外的尺寸规则详见 MDN:grid-auto-rows 。
使用网格线与 span 放置项目
.feature {
grid-column: 1 / -1;
}
/* Different representations spanning two columns in the same two-column explicit grid */
/* .feature { grid-column: span 2; } */
1 / -1 在 grid-column 中表示从显式网格的第一条列网格线到最后一条列网格线。它适用于占据整个网格宽度的标题或突出显示区域,无论是两列布局还是单列布局。负数网格线编号是相对于显式网格的末尾计算的,并不代表所有自动生成轨道的结束。如何调整重复列的数量和最小尺寸在 CSS Grid:repeat、auto-fit、auto-fill 与网格区域 中进行了比较。
span 2 意味着占据两个网格轨道,如果你没有指定具体的起始网格线,自动放置将决定位置。在移动设备上,如果你只有一列并保持 span 2,你可能会意外创建一个额外的列。如果你想保持全宽,请使用 1 / -1 或在移动设备上重新指定 span 值。当你最小化放置规格时,任何剩余的项目将默认放置在 HTML 顺序中的空单元格中。
运行完整的网格示例
将以下代码保存为 grid-basics.html ,以 UTF-8 编码保存并在浏览器中打开。在两列布局下,A、B 位于第一条固定高度行,C 在下一条隐式行跨越两列,D、E 位于再下一行。视口宽度不超过 480px 时改为一列:A 独占 80px 的第一行,其余项目依次放入隐式行,C 仍跨越网格全宽。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>grid-basics.html</title>
<style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
grid-template-rows: 80px; grid-auto-rows: minmax(100px, auto); gap: 16px;
width: min(100%, 640px); }
.grid > div { min-width: 0; padding: 12px; background: #dceefa; overflow-wrap: anywhere; }
.feature { grid-column: 1 / -1; }
@media (max-width: 480px) { .grid { grid-template-columns: minmax(0, 1fr); } }
</style>
</head>
<body>
<h1>Column proportions and row heights</h1>
<div class="grid"><div>A: first row</div><div>B: first row</div><div class="feature">C: Area that occupies two columns. As the content grows, the height of this auto-row also increases.</div><div>D: next line</div><div>E: This card has a long description. The height you need will vary depending on the length of your content. Instead of forcing all content to fit at a fixed height, set it to accommodate content beyond the minimum height.</div></div>
</body>
</html>
- 在宽屏上,确保 .grid 的宽度为640px,并在开发者工具中打开显示网格。列宽为208px·416px,列间距为16px。如果将列比例改为1fr·1fr,则每列变为312px。对比后,恢复为1fr·2fr。
- 第一行的高度为80px。如果在A中添加多行文本,行高本身将保持不变,内容可能会溢出。如果将文本恢复到原始状态并将grid-template-rows改为minmax(80px, auto),它可以根据内容增长。
- 适当增加 C 的内容。grid-auto-rows 的值为 minmax(100px, auto),因此行高可以大于 100px。仅将 grid-auto-rows 改为 100px,并观察固定行的差异,然后将其恢复到原始值。
- 如果你只是移除 C 的 grid-column 声明,C 将会被放置在一个单元格中,并且其后面项目的位置也会发生变化。再次恢复为 1/-1。在视口宽度不超过 480px 时查看整体宽度规格是否在 1 列中保持。
在窄屏幕上处理长内容
由于 Grid 的 1fr 轨道默认的自动最小尺寸,长字符串可以使轨道变宽。minmax(0, 1fr) 是设置轨道最小尺寸为 0 的方法,而字符串中的实际换行需要单独的规则。根据情况,min-width: 0 也会应用到项目本身。将以下代码保存为 grid-long-text.html。如果项目超过列,请查看 CSS 溢出、长文本换行与省略号 了解长字符串换行规则。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>grid-long-text.html</title>
<style>
* { box-sizing: border-box; }
body { margin: 16px; font: 16px/1.6 sans-serif; color: #243447; }
h1 { font-size: 24px; } h2 { font-size: 20px; margin-top: 32px; }
a { color: #145f8f; } a:focus-visible { outline: 3px solid #b4470b; outline-offset: 3px; }
.grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px;
width: min(100%, 600px); }
.grid > div { padding: 12px; background: #e8f5de; overflow-wrap: anywhere; }
</style>
</head>
<body>
<h1>Grid minimum size and long strings</h1><div class="grid"><div>ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</div><div>A description of ordinary length</div></div>
</body>
</html>
- 只需将 overflow-wrap 更改为 normal,以确认即使保持轨道宽度,字母也可以溢出。
- 如果你将两列都替换为 1fr 1fr,你可以看到长字符串的最小尺寸如何影响列的分布。比较之后,我们将两者恢复为 minmax(0, 1fr) 和 anywhere。
根据内容的实际阅读宽度选择响应式转换点,而不是设备名称。本例中的 480px 是一个学习选择,并不是所有网格的标准。你可以缩小屏幕并放大文本,以查看固定行、长字符串和由跨列创建的额外列,以帮助你找出溢出的原因。





