学完这篇你能独立用 CSS Grid 写出后台管理布局、响应式卡片墙和图文混排页面,不用再靠 float、flex 嵌套和一堆媒体查询硬凑。
第一步:分清容器和项目
Grid 只有两个角色:容器(设了 display: grid 的元素)和项目(它的直接子元素)。只有直接子元素受网格控制,孙子元素不管。
.container {
display: grid; /* 块级网格 */
/* display: inline-grid; 行内网格,用得少 */
}
写完之后页面看起来毫无变化——因为还没划格子,默认只有一列,项目从上往下堆。别慌,这是正常的。
注意:display: grid 只对直接子元素生效。如果你把子元素包了一层 <div>,那层包装才是项目,里面的东西得单独再设网格。
第二步:划列和划行
.container {
display: grid;
grid-template-columns: 200px 1fr 200px; /* 三列:固定-自适应-固定 */
grid-template-rows: 60px auto; /* 两行 */
gap: 16px; /* 行列间距,替代 margin 拼缝 */
}
三个关键词记牢:
- px / % / rem:固定尺寸
fr:剩余空间的比例份额,1fr 2fr 表示后者拿两倍
repeat():repeat(3, 1fr) 等于 1fr 1fr 1fr
minmax(200px, 1fr):小不小于 200px,大按比例分
注意:1fr 的最小值是 auto,遇到长英文单词或宽表格会被撑破。稳妥写法是 minmax(0, 1fr),这一条能救掉八成的"布局莫名溢出"。
第三步:用命名区域排版
给每个项目起名,然后像画图一样描述布局,改动结构时只改一处:
.layout {
display: grid;
grid-template-columns: 220px 1fr;
grid-template-rows: 64px 1fr 48px;
grid-template-areas:
"sidebar header"
"sidebar main"
"sidebar footer";
min-height: 100vh;
gap: 12px;
}
.layout > .header { grid-area: header; }
.layout > .sidebar { grid-area: sidebar; }
.layout > .main { grid-area: main; }
.layout > .footer { grid-area: footer; }
每行字符串里的列数必须一致,名字相同的相邻格子会自动合并成一块。空格用 . 占位表示留空。
注意:grid-area 的名字大小写敏感,且不能加引号。名字写错不会报错,只会整块跑到自动位置上去,排查时优先看这里。
第四步:精确投放单个项目
不想用区域名时,直接按网格线编号投放。线的编号从 1 开始,-1 表示最后一条线:
.banner {
grid-column: 1 / 3; /* 从第 1 条线到第 3 条线,占两列 */
grid-row: 2 / 4;
}
/* 等价简写 */
.banner { grid-column: span 2; } /* 从当前位置往后跨两列 */
跨列是卡片墙错落感的来源:让第一个卡片 grid-column: span 2,其余自然回流。
注意:没指定位置的项目会被自动放置填充空格。如果你手动放了一个项目却没设 grid-row,它可能被自动算法挪到别处,出现"我明明写了第 3 列"的情况。手动定位时行列一起写。
第五步:响应式卡片墙,零媒体查询
这是 Grid 最实用的一个技巧:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
屏幕越宽列数越多,窄到放不下 240px 就自动减列,一行媒体查询都不用写。
auto-fit 和 auto-fill 的区别:项目不够填满一行时,auto-fit 会把空轨道折叠、让现有项目拉宽;auto-fill 保留空轨道。卡片墙用 auto-fit,固定栅格用 auto-fill。
注意:卡片里放图片时,加一句 .cards img { width: 100%; display: block; }。行内图片天生带基线空隙,会让卡片高度参差。
第六步:对齐,别和 Flex 记混
Grid 有两套对齐属性,作用对象完全不同:
.grid {
justify-items: center; /* 单元格内,项目水平方向 */
align-items: stretch; /* 单元格内,项目垂直方向 */
justify-content: space-between; /* 整个网格在容器内的水平分布 */
align-content: start; /* 整个网格在容器内的垂直分布 */
}
单个项目想脱离群体,在项目上加 justify-self / align-self。
注意:justify-content 生效的前提是网格总宽度小于容器。如果列已经用了 1fr 撑满,改这个属性不会有任何反应,这是最常见的"属性写了没效果"。
第七步:项目实战——图文详情页
把前面的东西拼起来:
<article class="post">
<img src="cover.jpg" alt="">
<h2>标题</h2>
<p>正文段落……</p>
</article>
.post {
display: grid;
grid-template-columns: 320px 1fr;
grid-template-areas:
"cover title"
"cover body";
gap: 20px 24px;
align-items: start;
}
.post img { grid-area: cover; width: 100%; border-radius: 8px; }
.post h2 { grid-area: title; margin: 0; }
.post p { grid-area: body; margin: 0; min-width: 0; }
@media (max-width: 640px) {
.post {
grid-template-columns: 1fr;
grid-template-areas: "title" "cover" "body";
}
}
左侧配图、右侧标题加正文,窄屏一行代码切换成上下堆叠,顺序也一并调整了——这正是 Grid 比 flex 嵌套强的地方。
兼容性方面,2017 年后的主流浏览器全支持,不需要加厂商前缀,IE11 的旧语法可以忽略不管。
小结
- 容器设
display: grid,只有直接子元素是项目
- 划格子用
grid-template-columns / rows,fr 分配剩余空间,repeat() 简化重复
- 稳妥写法:
minmax(0, 1fr),避免内容撑破网格
- 命名区域
grid-template-areas 改布局最省心,列数必须对齐
- 单项目定位用
grid-column / grid-row,从 1 开始编号,-1 是最后一条线
- 响应式卡片墙一行搞定:
repeat(auto-fit, minmax(240px, 1fr))
justify-items 管格子内,justify-content 管整个网格,别搞混