Grid 常见示例、坑点与调试
常见布局示例
1. 两栏应用布局
.app {
display: grid;
grid-template-columns: 280px minmax(0, 1fr);
min-height: 100vh;
}
.main {
min-width: 0; /* 关键:允许主内容收缩 */
}
@media (max-width: 768px) {
.app {
grid-template-columns: 1fr;
}
}
minmax(0, 1fr) 和 min-width: 0 双保险,避免长文本、代码块或不可收缩内容撑破主内容列。
2. 经典圣杯布局
.page {
display: grid;
grid-template:
"header header header" auto
"nav main aside" 1fr
"footer footer footer" auto
/ 200px minmax(0, 1fr) 240px;
min-height: 100vh;
}
一段 grid-template 同时表达了区域、行高和列宽,结构一目了然。
3. 卡片末尾按钮对齐
.card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
.card {
display: grid;
grid-template-rows: auto 1fr auto; /* 标题 / 正文弹性 / 按钮 */
}
即使每张卡片正文长度不同,第三行的按钮也能靠底对齐。(想让不同卡片之间也严格对齐,需要 subgrid。)
4. 元素居中
.container {
display: grid;
place-items: center; /* 水平 + 垂直居中 */
min-height: 100vh;
}
只居中单个子元素:
.item {
place-self: center;
}
5. 自适应表单
.form {
display: grid;
grid-template-columns: max-content minmax(0, 1fr);
gap: 12px 16px;
align-items: center;
}
.form label { justify-self: end; }
/* 占满一整行的字段(如多行文本框、提交按钮)*/
.form .full { grid-column: 1 / -1; }
@media (max-width: 600px) {
.form {
grid-template-columns: 1fr; /* 窄屏改为上下堆叠 */
}
.form label { justify-self: start; }
}
6. 图文重叠的 Hero 区
.hero {
display: grid;
}
.hero > * {
grid-area: 1 / 1; /* 全部放到同一格,形成重叠 */
}
.hero-text {
place-self: center;
z-index: 1;
}
这比 position: absolute 更安全:容器高度依然由最高的内容撑起,不会塌陷。
7. 顶栏底栏固定、中间独立滚动
.shell {
display: grid;
grid-template-rows: 56px minmax(0, 1fr) 48px;
height: 100dvh;
}
.shell-body {
overflow-y: auto; /* 配合 minmax(0, 1fr) 才能正确滚动 */
}
🔑 这里的
minmax(0, 1fr)不可省。写成1fr时,行的最小高度会被内容撑开,overflow-y: auto不会生效,变成整页滚动。
容易踩坑的细节
1fr 仍然可能溢出
Grid Item 默认的最小尺寸相当于 min-width: auto,会尊重内容的最小宽度。长 URL、pre、表格都可能撑破轨道。
/* 三道保险,按需叠加 */
.container { grid-template-columns: 240px minmax(0, 1fr); }
.main { min-width: 0; }
.content { overflow-wrap: anywhere; }
height: 100% 不一定生效
百分比高度依赖包含块已有明确高度。页面级布局更常用:
.page {
min-height: 100vh;
min-height: 100dvh; /* 支持 dvh 的浏览器会覆盖上一行 */
}
dvh 会动态考虑移动端地址栏伸缩,100vh 作为兼容回退。
Grid Item 的 z-index
Grid Item 即使没有设置 position,也可以直接用 z-index 控制重叠层级:
.hero-image { grid-area: 1 / 1; }
.hero-text { grid-area: 1 / 1; z-index: 1; }
DOM 顺序与视觉顺序
通过网格线、命名区域、order 或 dense 改变视觉位置,不会同步改变 DOM、阅读和键盘焦点顺序。先保证 HTML 顺序符合语义,再用 Grid 做视觉布局。
Grid 与绝对定位
绝对定位元素脱离正常的 Grid 自动布局,但如果它的包含块是 Grid Container(容器设了 position: relative),仍可用网格线确定定位区域:
.container { position: relative; display: grid; }
.badge { position: absolute; grid-area: 2 / 3; }
除装饰性重叠外,应优先让内容留在正常网格流中。
gap 不能用百分比叠加在溢出计算上
/* ❌ 100% 已经吃满,gap 只能往外溢 */
grid-template-columns: 50% 50%;
gap: 20px;
调试方法
- 在开发者工具中选中 Grid Container,开启 Grid Overlay(Chrome / Firefox 都内置)。
- 打开「显示线号」「显示区域名」「显示轨道尺寸」三个开关,直接对照 CSS 里写的编号。
- 看问题出在显式轨道还是浏览器生成的隐式轨道(Overlay 中隐式轨道的线为虚线)。
- 遇到溢出:依次检查 Item 默认最小尺寸、不可换行内容、固定宽度与百分比轨道。
- 遇到位置异常:检查结束线编号是否写多了一格,以及
grid-auto-flow: dense是否改变了视觉顺序。 - 遇到高度异常:临时加
align-items: start验证是不是默认stretch造成的。
快速描边法,能立刻看清实际网格划分:
* { outline: 1px solid rgba(255, 0, 0, .3); }
选择 Grid 的判断方式
满足任一条件时,优先使用 Grid:
- 需要同时控制行和列。
- 多个元素需要共享统一的轨道和对齐线。
- 元素需要跨行、跨列或发生重叠。
- 页面结构能清晰表达为命名区域。
- 希望用
auto-fit + minmax()构建无需媒体查询的响应式布局。
如果只需让一组元素沿一个方向排列、换行、对齐或分配空间,Flexbox 往往更简单。实际项目中,两者组合使用通常是最佳方案。