CSS Grid 是专为二维布局设计的系统。如果说 Flexbox 擅长一维布局(行或列),那 Grid 就是处理复杂网格布局的利器。它让曾经需要复杂 CSS 技巧才能实现的布局变得简单直观。
基本概念#
容器与项目#
<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>.grid-container { display: grid; /* 或 inline-grid */}核心术语#
- 网格线(Grid Line):构成网格结构的分界线
- 网格轨道(Grid Track):两条相邻网格线之间的空间(行或列)
- 网格单元(Grid Cell):四条网格线围成的最小单位
- 网格区域(Grid Area):由多个网格单元组成的矩形区域
定义网格#
grid-template-columns / grid-template-rows#
定义列和行的尺寸:
.grid { display: grid; grid-template-columns: 200px 200px 200px; /* 三列,每列 200px */ grid-template-rows: 100px 100px; /* 两行,每行 100px */}fr 单位#
fr(fraction)表示剩余空间的比例:
.grid { grid-template-columns: 1fr 2fr 1fr; /* 比例 1:2:1 */}
.grid { grid-template-columns: 200px 1fr; /* 固定 + 自适应 */}repeat() 函数#
简化重复定义:
.grid { grid-template-columns: repeat(3, 1fr); /* 三列等宽 */ grid-template-columns: repeat(4, 100px 200px); /* 重复模式 */}minmax() 函数#
定义尺寸范围:
.grid { grid-template-columns: repeat(3, minmax(200px, 1fr)); /* 每列最小 200px,最大平分剩余空间 */}auto-fill 和 auto-fit#
自动填充列数:
/* 自动创建尽可能多的 200px 列 */.grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));}auto-fill vs auto-fit:
auto-fill:保留空列的空间auto-fit:空列会塌缩,内容列会扩展填满
/* 容器宽 800px,项目 2 个 */.auto-fill { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* 创建 4 列,后 2 列为空但占空间 */}
.auto-fit { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* 2 列,每列 400px */}间距#
.grid { gap: 20px; /* 行列间距相同 */ gap: 20px 10px; /* 行间距 列间距 */ row-gap: 20px; column-gap: 10px;}放置项目#
基于网格线#
网格线从 1 开始编号:
.item { grid-column-start: 1; grid-column-end: 3; /* 跨越第 1 到第 3 条列线(即前两列) */ grid-row-start: 1; grid-row-end: 2;}
/* 简写 */.item { grid-column: 1 / 3; grid-row: 1 / 2;}
/* 更简写 */.item { grid-area: 1 / 1 / 2 / 3; /* row-start / col-start / row-end / col-end */}span 关键字#
指定跨越的单元格数:
.item { grid-column: 1 / span 2; /* 从第 1 列开始,跨 2 列 */ grid-row: span 3; /* 跨 3 行 */}负数网格线#
从末尾开始计数:
.full-width { grid-column: 1 / -1; /* 从第一列到最后一列 */}网格区域#
命名区域#
.grid { display: grid; grid-template-columns: 200px 1fr 200px; grid-template-rows: auto 1fr auto; grid-template-areas: 'header header header' 'sidebar main aside' 'footer footer footer'; min-height: 100vh;}
.header { grid-area: header;}.sidebar { grid-area: sidebar;}.main { grid-area: main;}.aside { grid-area: aside;}.footer { grid-area: footer;}使用 . 表示空单元格:
.grid { grid-template-areas: 'header header header' 'sidebar main .' 'footer footer footer';}对齐#
容器级对齐#
.grid { /* 项目在单元格内的对齐(所有项目) */ justify-items: start | end | center | stretch; align-items: start | end | center | stretch; place-items: center; /* 简写 */
/* 整个网格在容器内的对齐 */ justify-content: start | end | center | space-between | space-around | space-evenly; align-content: start | end | center | space-between | space-around | space-evenly; place-content: center;}项目级对齐#
.item { justify-self: start | end | center | stretch; align-self: start | end | center | stretch; place-self: center;}隐式网格#
当项目超出定义的网格时,浏览器会自动创建隐式轨道:
.grid { grid-template-columns: repeat(3, 1fr); /* 只定义了列,行会自动生成 */
grid-auto-rows: 100px; /* 隐式行的高度 */ grid-auto-columns: 1fr; /* 隐式列的宽度 */ grid-auto-flow: row; /* 自动放置方向:row | column | dense */}dense 紧凑排列#
.grid { grid-auto-flow: row dense; /* 自动填补空白,可能打乱视觉顺序 */}实战案例#
响应式卡片网格#
.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.5rem;}
.card { background: white; border-radius: 12px; padding: 1.5rem; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);}无需媒体查询,自动响应容器宽度。
圣杯布局#
.layout { display: grid; grid-template-columns: 200px 1fr 200px; grid-template-rows: auto 1fr auto; grid-template-areas: 'header header header' 'nav main aside' 'footer footer footer'; min-height: 100vh; gap: 1rem;}
.header { grid-area: header; padding: 1rem; background: #1f2937; color: white;}
.nav { grid-area: nav; padding: 1rem; background: #f3f4f6;}
.main { grid-area: main; padding: 1rem;}
.aside { grid-area: aside; padding: 1rem; background: #f3f4f6;}
.footer { grid-area: footer; padding: 1rem; background: #1f2937; color: white;}
/* 响应式 */@media (max-width: 768px) { .layout { grid-template-columns: 1fr; grid-template-areas: 'header' 'nav' 'main' 'aside' 'footer'; }}仪表板布局#
.dashboard { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: auto auto 1fr; gap: 1rem; padding: 1rem;}
.stat-card { padding: 1.5rem; background: white; border-radius: 8px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);}
.chart-large { grid-column: span 2; grid-row: span 2;}
.chart-small { grid-column: span 2;}
.table-full { grid-column: 1 / -1;}图片瀑布流#
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-auto-rows: 10px; gap: 10px;}
.gallery-item { border-radius: 8px; overflow: hidden;}
/* 根据图片高度设置不同的 span */.gallery-item.tall { grid-row: span 30;}
.gallery-item.medium { grid-row: span 20;}
.gallery-item.short { grid-row: span 15;}
.gallery-item img { width: 100%; height: 100%; object-fit: cover;}表单布局#
.form { display: grid; grid-template-columns: 120px 1fr; gap: 1rem; align-items: center;}
.form label { text-align: right; color: #6b7280;}
.form input,.form textarea { padding: 0.5rem; border: 1px solid #d1d5db; border-radius: 6px;}
.form-full { grid-column: 1 / -1;}
.form-actions { grid-column: 2; display: flex; gap: 0.5rem;}<form class="form"> <label>用户名</label> <input type="text" />
<label>邮箱</label> <input type="email" />
<label>简介</label> <textarea rows="4"></textarea>
<div class="form-actions"> <button type="submit">保存</button> <button type="button">取消</button> </div></form>Grid vs Flexbox#
| 场景 | Grid | Flexbox |
|---|---|---|
| 一维布局(行或列) | 可以,但杀鸡用牛刀 | ✅ 最佳选择 |
| 二维布局(行和列) | ✅ 最佳选择 | 需要嵌套 |
| 内容驱动布局 | 需要知道内容结构 | ✅ 自动适应内容 |
| 精确控制布局 | ✅ 网格线精确定位 | 受限于主轴方向 |
| 响应式网格 | ✅ auto-fill/auto-fit | 需要手动计算 |
| 项目对齐 | 两个方向都容易 | 主轴容易,交叉轴需技巧 |
🎯 最佳实践:
- 页面整体布局:用 Grid
- 组件内部布局:用 Flexbox
- 复杂网格:用 Grid
- 单行/单列内容:用 Flexbox
两者可以嵌套使用:
.page { display: grid; grid-template-columns: 250px 1fr;}
.navbar { display: flex; justify-content: space-between;}
.card-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));}
.card { display: flex; flex-direction: column;}常见问题#
🤔 网格项目没有填满单元格?
默认 align-items 和 justify-items 是 stretch,检查是否被覆盖了。
🤔 如何让某个项目跨越整行?
.full-row { grid-column: 1 / -1;}🤔 grid-template-areas 里的名字可以重复吗?
可以,同名区域会合并成一个矩形。但必须是矩形,L 形或不规则形状无效。
🤔 如何调试 Grid 布局?
Chrome/Firefox 开发者工具有专门的 Grid 调试器,可以可视化网格线和区域。
Grid 让复杂的二维布局变得简单。结合 Flexbox,你几乎可以实现任何设计稿。下一篇我们将学习响应式设计,掌握媒体查询和移动优先策略。