Grid 布局
📐 CSS Grid 是面向二维行列结构的布局模型。下方子页面按“基础 → 属性 → 兼容性 → 注意事项”组织。
共同参考
Grid 布局:基础概念与使用方法
什么是 Grid 布局
CSS Grid 是二维布局系统,可同时控制行与列。适合页面级骨架、卡片宫格、 holygrail、仪表盘等「行列都要对齐」的场景。
核心术语:
- Grid 容器:
display: grid/inline-grid - Grid 项目:容器的直接子元素
- 网格线(grid line):划分轨道的线,从 1 开始编号
- 轨道(track):两条相邻线之间的行或列
- 单元格(cell):行列交叉的最小单位
- 区域(area):一个或多个单元格组成的矩形
- 间隙(gap):轨道之间的间距
如何启用
.container {
display: grid;
/* 或 */
display: inline-grid;
}
启用后,直接子元素成为网格项目;默认生成「单列多行」(每项占一行),需用模板属性定义多列。
最小可用示例
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
三列等宽,间距 16px;项目按源顺序自动填充。
与 Flex 的直觉对比
| Flex | Grid | |
|---|---|---|
| 维度 | 一维(行或列) | 二维(行和列) |
| 内容驱动 vs 布局驱动 | 更偏内容流 | 更偏预设轨道 |
| 典型用途 | 组件内对齐、导航 | 页面骨架、宫格 |
| 重叠/跨格 | 较弱 | 天然支持跨行跨列 |
二者常组合:外层 Grid 搭骨架,内层 Flex 做对齐。
定义网格的两种思路
1. 显式轨道
.layout {
display: grid;
grid-template-columns: 200px 1fr 1fr;
grid-template-rows: auto 1fr auto;
gap: 24px;
min-height: 100vh;
}
2. 命名区域(可读性极强)
.layout {
display: grid;
grid-template-areas:
"header header header"
"nav main aside"
"footer footer footer";
grid-template-columns: 200px 1fr 240px;
grid-template-rows: auto 1fr auto;
}
.header { grid-area: header; }
.nav { grid-area: nav; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
自动放置 vs 手动放置
- 自动:不写定位,按
grid-auto-flow填充 - 手动:
grid-column/grid-row/grid-area指定占位
.featured {
grid-column: 1 / 3; /* 从第 1 条竖线到第 3 条 */
grid-row: 1 / 2;
}
fr 单位与 minmax
1fr:分配剩余空间的一份弹性单位minmax(min, max):轨道尺寸夹在最小最大之间
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
这是响应式卡片宫格的经典写法,无需手写大量断点。
适用场景
- 整页布局(头/侧/主/脚)
- 卡片墙、图片墙、产品列表
- 表单多列表格化排列
- 仪表盘 modular 区块
- 需要元素跨行跨列或对齐到同一网格线
学习路径
grid-template-columns/rows+gaprepeat/fr/minmax/auto-fit- 线号定位与
grid-area - 对齐属性
justify/align-items/content - 隐式网格与
grid-auto-* - 兼容性与注意事项
相关条目:容器属性、项目属性、兼容性、注意事项、与 Flex 选型对比。
Grid 容器属性详解
容器属性地图
| 类别 | 属性 |
|---|---|
| 模板 | grid-template-columns / rows / areas |
| 简写 | grid-template、grid |
| 间隙 | gap / row-gap / column-gap |
| 隐式网格 | grid-auto-columns / rows / flow |
| 对齐 | justify-items / align-items / place-items |
| 轨道整体 | justify-content / align-content / place-content |
grid-template-columns / rows
定义显式列/行轨道。
.container {
display: grid;
grid-template-columns: 200px 1fr 2fr;
grid-template-rows: auto 1fr auto;
}
常用轨道尺寸
| 写法 | 含义 |
|---|---|
px / rem / % | 固定或相对长度 |
fr | 剩余空间弹性份数 |
auto | 由内容/最大内容等决定 |
min-content / max-content | 内容最小/最大理想尺寸 |
minmax(a, b) | 夹在 a~b |
fit-content(200px) | 类似 min(max-content, max(min-content, 200px)) |
repeat(n, …) | 重复轨道定义 |
repeat 与响应式
/* 固定 4 列 */
grid-template-columns: repeat(4, 1fr);
/* 自动填满:列宽至少 240px,能放几列放几列 */
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
/* 自动适配:必要时拉伸列以吃掉尾部空轨 */
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
- auto-fill:即使后面是空的,也尽量保留「可能的空列」结构
- auto-fit:空列会被折叠,已有列可伸展填满
多数卡片墙用 auto-fit + minmax 更直观。
grid-template-areas
用名字画结构,必须构成矩形区域。
.page {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"sidebar header"
"sidebar main"
"sidebar footer";
gap: 0;
min-height: 100vh;
}
.sidebar { grid-area: sidebar; }
.header { grid-area: header; }
.main { grid-area: main; }
.footer { grid-area: footer; }
.表示空单元格- 同一名字必须形成矩形,不能 L 形
媒体查询里可直接重排 areas,非常适合响应式骨架。
@media (max-width: 768px) {
.page {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"sidebar"
"footer";
}
}
gap
.container {
gap: 16px;
/* row-gap column-gap */
gap: 12px 24px;
}
gap 不增加边缘外边距;比用 margin 模拟轨道间距更干净。Grid 的 gap 支持早于 Flex,兼容性通常更好(见兼容性篇)。
隐式网格
项目超出显式轨道时,会创建隐式行/列。
.container {
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(100px, auto);
grid-auto-flow: row; /* 默认按行填充 */
}
grid-auto-flow | 行为 |
|---|---|
row | 逐行放(默认) |
column | 逐列放 |
row dense / column dense | 尽量回填空洞 |
dense 可能打乱视觉源顺序,注意无障碍。
对齐:items vs content
项目在单元格内(items)
.container {
justify-items: stretch; /* 水平,默认 stretch */
align-items: stretch; /* 垂直,默认 stretch */
place-items: center; /* align + justify 简写 */
}
常用值:start | end | center | stretch。
整个网格在容器内(content)
当网格总尺寸小于容器时:
.container {
justify-content: center;
align-content: start;
place-content: start center;
}
取值类似 Flex 的 content 分布:space-between、space-around 等。
命名网格线
.container {
grid-template-columns: [full-start] 1fr [main-start] 640px [main-end] 1fr [full-end];
}
.item {
grid-column: main-start / main-end;
}
便于与设计系统的「内容最大宽 + 全宽通栏」模式配合。
实用模式
圣杯 / 后台框架
.app {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: 56px 1fr;
grid-template-areas:
"nav top"
"nav body";
height: 100vh;
}
响应式卡片
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
gap: 1rem;
}
min(100%, 260px) 可避免小屏下 minmax 最小轨道导致溢出。
十二栏系统(简化)
.grid-12 {
display: grid;
grid-template-columns: repeat(12, 1fr);
gap: 16px;
}
.span-6 { grid-column: span 6; }
.span-4 { grid-column: span 4; }
速记
- 先定轨道:
template-columns/rows或areas - 再定缝:
gap - 溢出轨道靠
auto-rows/columns+auto-flow - 单元格内对齐用
*-items,网格在容器内对齐用*-content
Grid 项目属性详解
项目属性总览
写在 Grid 项目上:
| 属性 | 作用 |
|---|---|
grid-column-start / end | 列起止网格线 |
grid-row-start / end | 行起止网格线 |
grid-column / grid-row | 上述简写 |
grid-area | 区域名或四线简写 |
justify-self / align-self | 单元格内单项对齐 |
place-self | align + justify 简写 |
order | 自动放置时的顺序权重 |
线号定位
网格线从 1 开始。N 列有 N+1 条竖线。
.item {
grid-column-start: 1;
grid-column-end: 3; /* 不包含第 3 条线之后的轨道,实际跨 2 列 */
grid-row: 2 / 4; /* 跨 2 行 */
}
简写形式
/* start / end */
grid-column: 1 / 3;
grid-row: 2 / span 2;
/* 只写起点,默认跨 1 轨 */
grid-column: 2;
/* span */
grid-column: span 2;
grid-column: 1 / span 3;
负数线号
-1 表示最后一条线,适合「贴右/贴底」:
.full-bleed {
grid-column: 1 / -1; /* 横跨所有显式列 */
}
grid-area
1. 使用 template areas 名称
.header { grid-area: header; }
2. 四值线号简写
/* row-start / column-start / row-end / column-end */
.item {
grid-area: 1 / 2 / 3 / 4;
}
可读性通常不如具名 area,复杂页面优先 grid-template-areas。
跨列跨行实战
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 120px;
gap: 12px;
}
.gallery__hero {
grid-column: span 2;
grid-row: span 2;
}
注意:跨轨后,后续自动放置可能产生「空洞」;可用 grid-auto-flow: dense 回填(会改变视觉顺序)。
单元格内对齐
默认项目 stretch 拉满单元格。
.icon-cell {
justify-self: center;
align-self: center;
/* 等价 */
place-self: center;
}
.toolbar-item {
place-self: end stretch; /* 垂直 end,水平 stretch */
}
取值:start | end | center | stretch 等。
若项目有固有宽高或 max-width,stretch 可能看不出效果。
order
与 Flex 类似,影响自动放置顺序,不改 DOM / 无障碍顺序。
.item-late { order: 1; }
.item-first { order: -1; }
手动指定了线号的项目仍按其定位放置;order 主要影响参与自动布局的项。
与绝对定位
position: absolute 的子项通常不按网格自动占位(不占用网格单元格流),但若容器为定位包含块,仍可相对容器定位。需要「占格」请用 grid 定位而不是 absolute(除非要重叠装饰层)。
Grid 原生支持重叠:多个项目可以定位到同一区域,再用 z-index 控制层叠。
.card-media { grid-area: 1 / 1; }
.card-overlay { grid-area: 1 / 1; place-self: end; z-index: 1; }
子网格 subgrid(进阶)
.parent {
display: grid;
grid-template-columns: subgrid; /* 在子项上使用 */
}
.child {
display: grid;
grid-column: span 3;
grid-template-columns: subgrid;
}
subgrid 让子级对齐父级轨道,适合卡片内部多列与外层网格严格对齐。兼容性见《Grid 浏览器兼容性》。
常见组合片段
主内容限宽 + 偶发通栏
.page {
display: grid;
grid-template-columns: 1fr min(70ch, 100%) 1fr;
}
.page > * {
grid-column: 2;
}
.page > .breakout {
grid-column: 1 / -1;
}
表单两列表签
.form {
display: grid;
grid-template-columns: max-content 1fr;
gap: 12px 16px;
align-items: center;
}
.form .full {
grid-column: 1 / -1;
}
调试提示
- DevTools 打开 Grid 徽章,查看线号与区域名
- 混淆 start/end 时,记住 end 线是开区间边界
- 跨度用
span往往比硬算 end 线更稳
Grid 浏览器兼容性
总体结论(2024–2026 实务)
- 标准 CSS Grid 在 Chrome / Edge / Firefox / Safari 及主流移动浏览器中已可作为默认布局方案
- 无需再把 Grid 当成「渐进增强可选项」(除非明确要支持 IE 或极老 WebView)
- 需单独评估的先进特性:
subgrid、masonry、部分新级联/容器查询组合
核心特性支持概况
| 特性 | Chromium | Firefox | Safari | IE11 |
|---|---|---|---|---|
display: grid | 完整 | 完整 | 完整 | 旧语法/部分 |
grid-template-* | 完整 | 完整 | 完整 | 有限 |
gap(grid) | 完整 | 完整 | 完整 | 不支持标准 gap |
fr / minmax / repeat | 完整 | 完整 | 完整 | 部分差异 |
| 命名 areas | 完整 | 完整 | 完整 | 弱 |
auto-fit / auto-fill | 完整 | 完整 | 完整 | 不可依赖 |
subgrid | 较新版本已支持 | 支持较早 | 16+ 等 | 无 |
masonry | 实验/有限 | 有实现进展 | 视版本 | 无 |
精确版本请以 Can I Use、MDN 与项目 browserslist 为准。工程上「Grid 基础」可视为基线能力。
IE10/IE11 历史包袱(遗留系统)
IE10/11 实现的是过时 Grid 语法,与现代标准不兼容,例如:
display: -ms-grid-ms-grid-columns/-ms-grid-rows- 子项
-ms-grid-column等
不建议手写双份布局去「完美支持 IE Grid」。可行策略:
- 产品放弃 IE,文档标明最低浏览器
- IE 降级为单列普通流 / 简单 float / block
- 用
@supports (display: grid)做增强
.layout {
/* 降级:单列 */
display: block;
}
@supports (display: grid) {
.layout {
display: grid;
grid-template-columns: 240px 1fr;
gap: 24px;
}
}
Autoprefixer 不能把标准 Grid 完整编译成 IE 旧 Grid。
gap 与旧前缀
- 现代引擎:直接用
gap - 极老环境曾见
grid-gap别名;新代码统一gap - Grid 的 gap 普及早于 Flex gap,但仍应用目标浏览器验证
subgrid
用途:子级网格继承父级轨道对齐(卡片内部字段与邻卡齐线等)。
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3;
}
兼容策略:
- 作为增强:无 subgrid 时卡片内部改用自有 grid/flex
- 用
@supports (grid-template-columns: subgrid)分支 - 不在最低支持面未覆盖时作为唯一实现路径
masonry(瀑布流)
原生 grid-template-rows: masonry 等仍处推进中,生产环境多数团队仍用:
- 多列 + 绝对定位算法库
- 或接受 CSS 多列
column-count的阅读顺序限制 - 或 Flex/Grid 近似方案
上线前确认目标浏览器是否正式支持,避免依赖实验旗标。
与容器查询、相对颜色等组合
Grid 常和以下特性一起用:
@container做组件级响应式列数min()/max()/clamp()写轨道:has()调整列模板
这些要比「基础 Grid」更新,应单独列入兼容矩阵,而不是默认「能用 Grid 就能用全部」。
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
gap: clamp(12px, 2vw, 24px);
}
min() 在现代浏览器广泛支持;若存在超老 WebView,需抽测。
推荐兼容策略
- browserslist 明确排除 IE(除非合同要求)
- 基础布局直接使用标准 Grid
subgrid/masonry/ 实验性值走@supports或 polyfill 替代方案- 关键页面提供不依赖 Grid 的可读降级(单列堆叠通常足够)
- 用真机/云测覆盖:iOS Safari、Android Chrome、企业内常见内核
@supports 模板
.gallery > * {
margin-bottom: 1rem; /* 降级间距 */
}
@supports (display: grid) {
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 1rem;
}
.gallery > * {
margin-bottom: 0;
}
}
测试清单
- 显式多列在窄屏是否溢出(
minmax+min(100%, …)) -
grid-template-areas在断点切换后名称是否仍匹配 - 隐式行高度与滚动容器
- 跨列项目 + 自动放置空洞
- 打印样式下网格是否可接受
- 目标最低 iOS/Android 版本的 gap、fr、repeat
实务建议
把 Grid 基础能力当作现代前端默认技能栈;把兼容精力集中在业务声明的最低浏览器,以及 subgrid 等增强特性,而不是为 IE 维护第二套网格语法。
Grid 注意事项与常见坑
1. minmax 最小轨道在小屏溢出
现象:repeat(auto-fit, minmax(300px, 1fr)) 在 320px 宽设备出现横向滚动。
原因:轨道最小 300px 大于容器。
解法:
grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
2. 1fr 与最小内容尺寸
1fr 等价于 minmax(auto, 1fr) 的历史行为会影响「能不能比内容更窄」。长单词、大图可能撑破 fr 轨道。
.item { min-width: 0; } /* 或 overflow: hidden / auto */
/* 轨道侧 */
grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
3. grid-template-areas 必须是矩形
同一区域名不能摆成 L / T 形,否则整段声明无效。
/* 无效示例概念:main 呈 L 形 */
/* 应拆成多个区域或改用线号定位 */
每行字符串代表一行,列数必须一致;用 . 占位空单元。
4. 隐式行高度失控
只定义了列、没定义行时,新增行走 grid-auto-rows(默认 auto)。等高卡片或虚拟滚动场景请显式:
grid-auto-rows: minmax(120px, auto);
/* 或 */
grid-auto-rows: 1fr; /* 需容器有明确高度才有「分份」意义 */
5. 百分比、fr 与 gap 混用的心智负担
gap 会从容器中先扣除再分 fr。用 % 列宽 + gap 时,总和可能超过 100% 导致溢出。优先 fr + gap,少用「多列百分比相加 = 100%」老套路。
6. 滚动只出现在某一网格区域
与 Flex 类似,需要:
.page {
height: 100vh;
display: grid;
grid-template-rows: auto 1fr;
}
.main {
min-height: 0; /* 关键 */
overflow: auto;
}
缺 min-height: 0(或 minmax(0, 1fr) 轨道)时,1fr 行往往被内容撑开。
7. dense 打乱阅读顺序
grid-auto-flow: dense 会回填空洞,视觉顺序可能与 DOM/Tab 不一致。装饰性瀑布可接受;表单、文章、结账流程慎用。
8. 只有直接子元素是 grid 项
包装多一层就不再占据你定义的 area。用 display: contents 可让子级「穿透」成为网格项,但要注意无障碍与浏览器差异,慎用。
9. align/justify 名字易混
| 目标 | 用 |
|---|---|
| 所有项目在各自单元格内 | justify-items / align-items |
| 单个项目 | justify-self / align-self |
| 整个网格在容器内(有多余空间时) | justify-content / align-content |
Flex 里没有 *-items 对「单元格」这层,从 Flex 转 Grid 时最容易混。
10. 媒体查询与 areas 不同步
改了 grid-template-areas 却忘了改子项 grid-area 名称,或桌面 areas 有 aside、移动删除后未重置,会导致元素不显示或叠在错误位置。断点切换时做一次「名称对照表」。
11. 性能
- 超大网格(成百上千格)+ 频繁变更模板成本高,列表虚拟化优先
- 动画避免连续改
grid-template-columns长字符串;可动画transform或用固定模板 + 改 span - DevTools 打开 Grid 调试层检查线号,避免盲调
12. 与 Flex 嵌套时的职责
反模式:外层 Flex 硬模拟二维对齐。更清晰的分工:
- Grid:页面/区块二维结构
- Flex:导航、按钮组、卡片脚注对齐
快速自检表
- 小屏是否用了
min(100%, …)保护 minmax - 可收缩轨道/项目是否
minmax(0, 1fr)/min-width: 0 - areas 每行列数一致且为矩形
- 滚动容器链上有
min-height: 0 - 未在关键路径滥用 dense / order
- gap 与百分比列未叠加溢出
稳妥默认
.stack-grid {
display: grid;
gap: 1rem;
}
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
gap: 1rem;
}
.app-shell {
display: grid;
grid-template-rows: auto minmax(0, 1fr);
height: 100vh;
}
.app-shell > main {
overflow: auto;
min-height: 0;
}