CSS Grid 布局完全指南
写 CSS 的时候,很多人会下意识先掏 flex,然后发现“哎,怎么一换屏幕宽度就歪了”。我也踩过这个坑。前阵子给一个内容卡片页排布局,卡片标题、图片、标签、按钮要按顺序走,结果在窄屏下全挤成一坨。后来试着切到 CSS Grid,几行代码就把“行列对齐、间距自洽、顺序可调”全搞定了。那感觉就像突然把桌子从拼桌变成包厢——谁坐哪、留多大过道,心里有数。
你有没有过这种经历:设计稿上明明是三列不等宽,代码里却只能靠百分比和 margin 硬撑,最后一算像素差了两三像素就闹心。Grid 最讨喜的地方,是它不逼你“把一切都塞进一维”。flex 是排排队,Grid 是画格子。你可以直接说“这里横跨两列,那里占满剩余空间”,浏览器会帮你算好。最重要的是,它不跟 flex 打架——很多时候,它们是搭档:外层 Grid 决定大结构,内层 flex 照顾内容对齐。

举个接地气的例子:公司官网的首屏,左侧大块标题配副标题,右侧一张全出血图,下面还要放三条客户评价。以前我会用 float 或者绝对定位把图“扯”出来,结果字号一变就穿帮。换成 Grid 之后,写法简单得像记账:标题占两行三列,图片从第二列开始跨两列,评价区另起一行三等分。代码没超过三十行,屏幕一缩,媒体查询里改个 grid-template-columns,把结构一重排,该合并合并,该堆叠堆叠,稳稳当当。
再比如后台管理页的筛选区,常见的是“输入框 + 下拉框 + 日期区间 + 两个按钮”,设计要求在宽屏时按钮靠右,窄屏时按钮占满底行。如果用传统布局,不得不给按钮包个额外容器,再用浮动或者 flex 的间距技巧去推。Grid 可以直接用 grid-template-areas 把区域画出来,按钮声明在“actions”区域,宽屏时把它对齐到末尾,窄屏时让它独占一行。视觉上清爽,改需求时也少吵架——区域名字就是最直白的设计注释。
还有一个容易忽略的场景:间距。以前做等宽卡片,常用负 margin 抵消父级 padding,结果一不小心滚动条跑出来或者出现横向滚动。Grid 给了 grid-gap(现在叫 gap),只管“格子之间留多少”,不用操心塌陷问题。你甚至可以写 grid-row-gap 和 grid-column-gap,让行距和列距不同,版面呼吸感立刻就出来了。更妙的是,配合 minmax 和 auto-fit,不用写媒体查询也能让卡片自动“挤得下就并排,挤不下就折行”。这种弹性,是 Grid 藏在冷静外表下的温柔。
把骨架画出来:grid-template 的直觉用法
学 Grid,最容易卡住的是那一堆带线的名字。别怕,先把它当成画表格。你要做的第一件事,是告诉浏览器“我要几列、几行,每列多宽”。
.container {
display: grid;
grid-template-columns: 200px 1fr 2fr;
grid-template-rows: auto 100px;
}
上面这段话的意思是:三列,第一列固定 200 像素,第二列占一份剩余空间,第三列占两份。行高方面,第一行随内容走,第二行固定 100 像素。数字好理解,但项目里更常见的写法是:repeat、fr 和 minmax。
repeat 就是“别啰嗦”,比如 repeat(3, 1fr) 直接给你三列等宽。fr 的本质是“把剩下的地盘按比例分”,它不吃固定像素的地盘,先扣掉固定宽度,再分剩下的。这在很多后台布局里特别管用:左侧菜单固定 240 像素,右边 1fr,内容再多也不跑。
minmax 则是底线思维。写 minmax(280px, 1fr),意思是“最少 280 像素,最多占一份”。卡片列表用它,配合 auto-fit,就能写出“能排几个排几个,排不下就换行,还保证每张卡片不低于 280 像素”的效果。不用媒体查询,页面自己会呼吸。
如果你喜欢给区域起名字,可以用 grid-template-areas:
.container {
grid-template-areas:
"header header"
"aside main"
"footer footer";
}
然后在子元素上用 grid-area: header; 对号入座。名字一上眼,设计图和代码就对齐了,改布局的时候不用去猜“到底是第几个 div”。
最后一个小细节:间距别再用 margin 硬怼。写 gap: 24px;,行列间距一次到位。嵌套 Grid 时,gap 不会叠加成奇怪的大空白,视觉节奏更稳。
让元素“跨格子”:位置不是只能数数
很多人一开始以为 Grid 必须按源码顺序排,其实不是。Grid 最像电子表格,你可以指定“从第几条线开始,到第几条线结束”。
线(line)是 Grid 偷偷画的参考线。n 列就有 n+1 条线。写 grid-column: 2 / 4; 就是说“在第二条线开始,在第四条线结束”,横跨两列。还能用 span:grid-column: span 2;,意思是从当前位置跨两列。
配合命名线会更清晰:
.container {
grid-template-columns: [start] 1fr [center] 1fr [end];
}
.item {
grid-column: center / end;
}
代码读起来像在描述位置,而不是在算坐标。
有时候你不想硬写数字,想让浏览器自己找空位,可以用 auto 相关的值:grid-column: auto / span 2;。再加上 grid-auto-flow: dense;,Grid 会把后面的小元素往前塞,填补空缺。这对图片墙、产品列表特别有用,不用自己写复杂逻辑去“补位”。
还有对齐层面的“跨”:align-self 和 justify-self 控制单个元素在格子里怎么站。默认是 stretch,拉满整个格子;改成 center 就能居中。这比用 margin: auto 干净得多,也不会意外撑破父级。
响应式不是重写,是“换个规则”
做响应式最烦的不是写媒体查询,是“写了像没写”——改了这里,那里又歪了。Grid 让响应式更像在换一副棋盘,而不是在挪动棋子。
最常用的手段,是在媒体查询里改 grid-template-columns。宽屏三列,平板两列,手机一列,逻辑一目了然。更进一步,可以用 minmax 和 auto-fit 写“无断点”弹性:
.container {
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
这句话的意思是:自动放尽可能多的列,每列至少 280 像素,剩下的平分。屏幕宽就并排多些,窄了就少些,全程不用媒体查询。
但完全不用断点有时候会失控,比如标题和图片的视觉比重在不同设备不一样。这时候还是得靠 grid-template-areas,在不同断点重写“地图”。写法依然清爽:
@media (max-width: 768px) {
.container {
grid-template-areas:
"header"
"main"
"aside"
"footer";
}
}
区域重排,源码不动,样式表就是设计注释的延伸。
还有一个实用技巧:配合 min() 和 clamp() 做“智能宽度”。比如 grid-template-columns: repeat(3, min(300px, 100%));,当空间不够时,列会自动让出而不是溢出。再结合 gap,页面在不同设备上都不会出现“被挤扁”或者“留大片尴尬空白”的情况。
和 flex 组队,别打架
Grid 和 flex 不是二选一,而是分工。Grid 擅长“把大块地盘划分清楚”,flex 擅长“让小块内容对齐”。
常见模式是:Grid 做页面骨架,flex 做卡片内部。卡片里的标题、描述、按钮,用 flex 纵向排列或者横向分散对齐,不费力。Grid 保证卡片们在页面上不偏移,flex 保证卡片里不歪斜。
当你在 Grid 容器里写 display: flex,对齐也不会冲突。Grid 的 gap 负责卡片之间,flex 的 gap 负责卡片内部。这样写,改间距的时候不会互相覆盖,也不会出现“为什么加了 margin 却没反应”的玄学时刻。
有时候你会需要“某个元素突破网格”,比如全出血的图片。这时用 grid-column: 1 / -1; 就能让它占满所有列。再往里,图片本身用 flex 或 grid 继续细分,互不干扰。这种层层递进的结构,让代码读起来像目录,而不是绕口令。
结语
CSS Grid 并不神秘,它只是把“我们心里想要的对齐方式”翻译成浏览器听得懂的语言。画线、起名、分地盘,剩下的让它算。你不用再和 margin 搏斗,也不用在媒体查询里反复横跳。
上手的第一天可能会觉得属性多,但真正用起来,你会发现它出奇地稳。宽了不乱,窄了不挤,换顺序不用动结构,改间距不用猜塌陷。它不强迫你用一套规则解决所有问题,而是允许你在不同断点下,重新画一张更舒服的棋盘。
写页面说到底,是在和不确定性打交道:屏幕尺寸、内容多少、设备像素比,永远在变。Grid 给你的不是“终极答案”,而是一套“稳得住”的方法。把骨架画清楚,内容自然会各就各位。