一、先建立行列的概念
.grid {
display: grid;
grid-template-columns: 200px 1fr 1fr; /* 三列:固定 200 + 两个弹性 */
grid-template-rows: auto 1fr auto; /* 三行:头、主体、尾 */
gap: 16px;
}
子元素默认按顺序自动填充格子(行优先)。也可以用 grid-column / grid-row 指定跨格:
.hero { grid-column: 1 / -1; } /* 从第 1 条网格线到最后一条,即横跨整行 */
二、fr 是「剩余空间的比例」
1fr 不是「一份宽度」,而是「剩余空间的一份」。所以 200px 1fr 1fr 里,先扣掉 200px 和 gap,剩下的再平分给两个 1fr。
和 % 的区别很重要:% 是按容器总宽算,加上 gap 容易溢出;fr 自动扣除 gap,不需要手动计算。
三、一行搞定响应式
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
拆解:
repeat(auto-fit, ...):能放几个就放几个。minmax(240px, 1fr):每列最小 240px,最大占满剩余空间。
效果是:容器宽 1000px 时放 4 列,缩到 600px 自动变 2 列,手机上 1 列。全程不需要媒体查询。
auto-fit 与 auto-fill 的区别:空间有富余时,auto-fit 会把空轨道折叠、让现有列变宽;auto-fill 保留空轨道,列宽不变。做卡片列表通常用 auto-fit。
四、命名区域:给布局画草图
.page {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-columns: 200px 1fr;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
grid-template-areas 就像在代码里画了一张 ASCII 图,改布局只改这张图,可读性远高于算网格线。做移动端时只需重定义一次 areas:
@media (max-width: 640px) {
.page { grid-template-areas: "header" "main" "sidebar" "footer"; grid-template-columns: 1fr; }
}
五、对齐
justify-items/align-items:控制格子内元素的对齐。justify-content/align-content:控制整个网格在容器里的分布(网格比容器小时才有意义)。place-items: center是两者的简写,做居中很方便。
六、几个坑
1fr被内容撑破:1fr的最小值是auto,遇到长内容会撑开;用minmax(0, 1fr)强制可收缩。- gap 兼容:现代浏览器都支持,老版 Safari 需要前缀或改用 margin。
- 子元素
position: absolute:会脱离网格,定位以最近的定位祖先为准。 - 隐式行:子元素多于定义的格子时会自动新增行,高度由
grid-auto-rows控制。
七、Flex 还是 Grid
| 场景 | 推荐 |
|---|---|
| 导航栏、按钮组、标签列表 | Flex(一维) |
| 整页布局、卡片墙、图片网格 | Grid(二维) |
| 需要行列同时对齐 | Grid |
| 元素数量不定、需要自动换行 | Grid 的 auto-fit |
两者都支持 gap,也都能嵌套。实际项目里常见「Grid 搭页面骨架,Flex 排内部元素」。
小结
fr 分的是剩余空间;repeat(auto-fit, minmax(240px,1fr)) 一行实现响应式;grid-template-areas 让布局像画图;1fr 撑破时用 minmax(0,1fr)。