第六章 · 6.4 节
Grid 详解
如果说 Flexbox 是"一维"的排布工具,那 Grid 就是真正意义上的"二维"布局系统——它能同时控制行与列,让我们第一次可以用纯 CSS 精确描述报刊式的复杂版面,而不必依赖嵌套的 div 拼凑。
与 Flexbox 的分工
| Flexbox | Grid | |
|---|---|---|
| 维度 | 一维(一行或一列) | 二维(行与列同时) |
| 驱动方式 | 内容驱动,尺寸由内容撑开 | 布局驱动,先定义轨道再放内容 |
| 典型场景 | 导航栏、按钮组、卡片内部排布 | 页面整体骨架、图片墙、杂志排版 |
实战中二者并非互斥:常见做法是用 Grid 搭建页面级的整体骨架,再用 Flexbox 处理骨架内部每个区块的一维排列。
定义行与列
.layout { display: grid; grid-template-columns: 220px 1fr; grid-template-rows: 64px 1fr 48px; gap: 16px; }
grid-template-columns / grid-template-rows 用空格分隔的一串长度值定义"轨道"(track),每个值对应一条列或一行的尺寸。轨道之间天然形成"网格线"(grid line),从 1 开始编号,也可以用 repeat() 简化重复轨道:
.gallery { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
fr 单位
fr(fraction)是 Grid 专属的弹性单位,代表"分配剩余空间的份数",与 flex-grow 的思路相通,但更灵活——可以与固定长度混用:
.layout { grid-template-columns: 200px 1fr 2fr; /* 第一列固定 200px,剩余空间按 1:2 分给第二、三列 */ }
子项定位
子项可以用网格线编号,精确指定自己横跨的起止位置:
.hero { grid-column: 1 / 3; /* 从第 1 条线到第 3 条线,横跨 2 列 */ grid-row: 1 / 2; } /* span 关键字:横跨 N 条轨道,无需关心起止编号 */ .wide { grid-column: span 2; }
grid-template-areas:具名区域
把网格划分成语义化的命名区域,是 Grid 中最具可读性的用法——布局结构在 CSS 里"画"出来,一目了然:
.page { display: grid; grid-template-columns: 220px 1fr; grid-template-areas: "sidebar header" "sidebar main" "sidebar footer"; } .sidebar { grid-area: sidebar; } header { grid-area: header; } main { grid-area: main; } footer { grid-area: footer; }
. 可以留出空白区域,不分配给任何子项。auto-fit / auto-fill / minmax:自适应网格
这是 Grid 中最强大的组合技,能实现"不写媒体查询也能响应式"的卡片网格——根据容器宽度自动决定放几列。
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; }
minmax(200px, 1fr) 表示每列最小 200px、最大均分剩余空间;auto-fit 会自动计算能放下几列,并让已有列拉伸填满整行;auto-fill 则会保留"看不见"的空轨道位置,列不会被拉伸得过宽。二者的区别只有在剩余空间不足以再放一列时才会体现出来。
| 空间足够放下更多列时 | |
|---|---|
| auto-fit | 已有列拉伸,填满整行,不留空轨道 |
| auto-fill | 保留潜在空轨道的位置,已有列不额外拉伸 |
隐式网格
当子项数量超出 grid-template-* 定义的轨道数时,浏览器会自动生成"隐式轨道"来容纳多出的内容。用 grid-auto-rows / grid-auto-columns 控制这些隐式轨道的尺寸,grid-auto-flow: dense 则会让排布算法主动回填此前跳过的空隙。
.masonry-like { grid-auto-rows: 10px; grid-auto-flow: dense; }
对齐属性总览
Grid 的对齐属性与 Flexbox 一脉相承,但多了"针对整个网格"与"针对单个子项"两个维度:
| 属性 | 作用对象 | 方向 |
|---|---|---|
| justify-items | 所有子项 | 行内方向(水平) |
| align-items | 所有子项 | 块方向(垂直) |
| justify-self | 单个子项,覆盖 justify-items | 行内方向 |
| align-self | 单个子项,覆盖 align-items | 块方向 |
| justify-content | 整个网格(当轨道总宽小于容器时) | 行内方向 |
| align-content | 整个网格 | 块方向 |
实战:杂志式排版
结合具名区域、span 与 auto-fit,可以快速搭出一个左侧特写、右侧信息流的版面:
.magazine { display: grid; grid-template-columns: 2fr 1fr; grid-template-rows: repeat(3, auto); gap: 16px; } .feature { grid-row: span 3; } /* 左侧特写纵跨三行 */