Grid 网格布局:二维世界的布局王者,像下围棋一样掌控页面
如果说Flexbox是“一维战神”,擅长排排坐,那Grid就是“二维霸主”,能同时操控行和列。今天我们就来下这盘“布局围棋”,用网格思想彻底重构网页,让复杂布局变得像填格子一样简单。
前言
还记得小时候玩的方格本吗?一行一行,一列一列,规规矩矩。Grid布局就是把这种“方格本”思维带到了CSS里。你可以在页面上画出任意行、任意列,然后把元素放进去,想放哪格放哪格,甚至可以合并单元格——就像Excel表格,但比Excel灵活一万倍。
Grid是CSS布局的终极武器,尤其适合做页面整体架构、卡片墙、仪表盘这类需要同时控制行和列的场景。如果说Flexbox是特种兵,擅长单兵作战,那Grid就是指挥官,能调动千军万马。
一、Grid的核心概念:容器与项目,行与列
和Flexbox类似,Grid也是作用于父容器和直接子项目。只要在父元素上设置display: grid或display: inline-grid,你就开启了一个网格世界。
.container {
display: grid;
}
默认情况下,网格只有一列,行高由内容决定。要真正“画”出网格,你需要用grid-template-rows和grid-template-columns定义行和列。
二、定义网格:画出你的棋盘
1. 固定行高和列宽
你可以用各种单位定义行列的尺寸,比如像素、百分比、em等。
.container {
display: grid;
grid-template-columns: 200px 200px 200px; /* 三列,每列200px */
grid-template-rows: 100px 150px; /* 两行,第一行100px,第二行150px */
}
这样你就画了一个3列2行的网格,一共6个格子。项目会按顺序自动填充每个格子,就像表格里从左到右、从上到下填数据一样。
2. fr单位:分蛋糕神器
Grid引入了fr单位(fraction的缩写),表示剩余空间的比例分配。这比Flexbox的flex-grow更直观。
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* 三列,中间占两份,两边各占一份 */
}
如果父容器宽度是1200px,那么第一列占300px,第二列600px,第三列300px。fr可以和固定单位混用,比如200px 1fr 2fr,浏览器会先分配200px,剩下的按比例分。
3. repeat() 函数:偷懒必备
如果你要定义很多等宽的列,手动写很累。repeat()函数来救场。
.container {
grid-template-columns: repeat(3, 1fr); /* 三列等宽,相当于 1fr 1fr 1fr */
grid-template-rows: repeat(4, 100px); /* 四行,每行100px */
}
repeat()还可以组合不同模式,比如repeat(2, 100px 1fr)表示重复两次“100px 1fr”的序列,最终得到四列:100px、1fr、100px、1fr。
4. minmax():给尺寸一个范围
有时候我们希望列宽能在一定范围内弹性变化,比如最小200px,最大自适应。minmax()搞定。
.container {
grid-template-columns: minmax(200px, 1fr) 2fr; /* 第一列最小200px,可以放大到1fr,第二列固定2fr */
}
5. auto-fill 与 auto-fit:响应式利器
当列数不确定时,可以用auto-fill或auto-fit配合minmax实现类似“流动布局”的效果。
-
auto-fill:尽可能多地填充列,即使某些列是空的。 -
auto-fit:也是尽可能多地填充,但会把空列收缩为0,让有内容的列伸展。
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
这段代码的意思是:每列最小200px,如果容器足够宽,就放尽可能多的列,并且每列等宽;当容器变窄时,列数自动减少,每列仍不小于200px。这就是纯CSS实现的响应式卡片墙!
三、网格线:定位的坐标系
每个网格都由网格线划分。比如3列有4条纵向网格线(从1开始编号),2行有3条横向网格线。你可以用这些线来精确放置项目。
.item {
grid-column-start: 1;
grid-column-end: 3; /* 从第1条纵向线跨到第3条线,即占据前两列 */
grid-row-start: 1;
grid-row-end: 3; /* 从第1条横向线跨到第3条线,即占据前两行 */
}
简写为:
.item {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
也可以从哪条线开始,并指定跨度:
.item {
grid-column: 1 / span 2; /* 从第1列开始,跨2列,等同于1/3 */
grid-row: 1 / span 2;
}
网格线也可以命名,比如grid-template-columns: [main-start] 1fr [main-end],然后使用命名来定位。
四、网格区域:给格子起名字
如果你觉得用线编号不够直观,可以给网格区域命名。用grid-template-areas属性来划分区域。
.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
grid-template-rows: 100px 1fr 100px;
grid-template-areas:
"header header header"
"sidebar content aside"
"footer footer footer";
}
.header {
grid-area: header;
}
.sidebar {
grid-area: sidebar;
}
.content {
grid-area: content;
}
.aside {
grid-area: aside;
}
.footer {
grid-area: footer;
}
这个布局清晰得像图纸一样,每个区域的名字直接对应一个网格单元格。注意,grid-template-areas里的每个单元格必须填满,不能有空洞;可以用.表示空单元格。
五、间距与对齐:让网格透气
1. 行列间距
用gap属性设置网格线之间的间距,可以分别设置行间距和列间距:
.container {
gap: 20px; /* 行列间距都是20px */
row-gap: 10px; /* 单独设置行间距 */
column-gap: 15px; /* 单独设置列间距 */
}
2. 项目在单元格内的对齐
项目默认填满整个单元格,但你可以控制它们的位置。
-
justify-items:控制项目在单元格内水平方向的对齐(左中右)。 -
align-items:控制项目在单元格内垂直方向的对齐(上中下)。 - 取值:
start、end、center、stretch(默认)。
.container {
justify-items: center; /* 所有项目水平居中 */
align-items: center; /* 所有项目垂直居中 */
}
如果想单独控制某个项目,用justify-self和align-self。
3. 整个网格在容器内的对齐
如果网格的总尺寸小于容器,可以用justify-content和align-content控制网格整体的对齐,类似于Flexbox。
.container {
justify-content: center; /* 网格整体水平居中 */
align-content: center; /* 网格整体垂直居中 */
}
取值同样是start、end、center、space-between、space-around、space-evenly。
六、实战:用Grid搭建常见布局
1. 经典三栏布局(圣杯)
.container {
display: grid;
grid-template-columns: 200px 1fr 200px;
gap: 20px;
}
就这么简单,三栏就出来了,而且中间自适应。
2. 响应式卡片墙
我们希望卡片最小200px,尽量填满容器,而且自动换行。
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}
无论容器多宽,卡片都会自动调整列数,完美响应式。
3. 不规则布局:杂志风格
比如一个封面图占两列,下方三个卡片各占一列。
<div class="magazine">
<div class="feature">封面大图</div>
<div class="card">卡片1</div>
<div class="card">卡片2</div>
<div class="card">卡片3</div>
</div>
.magazine {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}
.feature {
grid-column: 1 / -1; /* 从第一列线到最后一列线,即占满整行 */
}
-1表示最后一条网格线,很方便。
4. 后台管理仪表盘
后台常有复杂区域划分,用grid-template-areas最合适。
.dashboard {
display: grid;
grid-template-columns: 250px 1fr 300px;
grid-template-rows: 80px 1fr 60px;
grid-template-areas:
"header header header"
"sidebar main widgets"
"footer footer footer";
height: 100vh;
}
各区域对号入座,结构一目了然。
5. 叠加效果
Grid还可以让多个元素重叠。通过给它们设置相同的网格区域,然后利用z-index控制层级。
.container {
display: grid;
grid-template-columns: 1fr 1fr;
}
.item1 {
grid-area: 1 / 1 / 2 / 3; /* 占满整行 */
background: red;
z-index: 1;
}
.item2 {
grid-area: 1 / 2 / 2 / 3; /* 只占第二列 */
background: blue;
opacity: 0.5;
z-index: 2; /* 显示在上层 */
}
七、Grid vs Flexbox:怎么选?
很多人纠结什么时候用Grid,什么时候用Flexbox。其实很简单:
- Flexbox:一维布局,适合控制元素在一条线上的排列(导航、按钮组、等分列表)。
- Grid:二维布局,适合同时控制行和列(页面整体架构、卡片墙、仪表盘)。
它们不是替代关系,而是配合关系。你可以在Grid单元格里用Flexbox排列内部元素,也可以把Flexbox项目里再嵌套Grid。两者结合,天下无敌。
八、常见坑点与避坑指南
1. 默认不是严格的一行一列
如果只设置display: grid而不定义行列,默认只有一列,行数由项目数量决定(每个项目占一行)。所以一定要定义行列。
2. 项目会自动填充,但可能超出网格
如果项目数量超过网格单元格,会自动创建隐式网格(新行),行高默认auto。你可以用grid-auto-rows控制隐式行的高度。
.container {
grid-auto-rows: 100px; /* 隐式创建的行高100px */
}
3. fr 和 minmax 结合时注意死循环
minmax(200px, 1fr)的意思是:优先让列宽为1fr,但不会小于200px。这通常没问题,但如果你把所有列都设成这样,且容器总宽度小于列数*200px,就会出现溢出(因为每列都强制不小于200px)。这时可以改用auto-fit和minmax的巧妙组合,或者用max-width限制。
4. gap 会占用 fr 空间
间隙是在分配fr之前扣除的。比如三列1fr,gap 20px,那么每列实际宽度 = (容器宽度 - 40px) / 3。所以计算时要考虑间隙。
5. 网格线编号从1开始,不是0
这个容易搞错。不过可以用-1表示最后一条线,比较方便。
九、总结
Grid布局是CSS给前端开发者的一份大礼,它把网页布局变成了一种直观、可预测的体验。核心要点:
- 用
grid-template-columns和grid-template-rows定义网格结构。 - 用
fr、repeat()、minmax()灵活控制尺寸。 - 用
grid-column/grid-row或grid-area放置项目。 - 用
gap控制间距,用justify/align控制对齐。 - 用
auto-fit和minmax实现响应式。 - 复杂布局用
grid-template-areas命名,代码如设计图。
Grid不难,关键是多动手画格子。一旦你习惯了这种“下围棋”式的布局思维,你会发现以前那些棘手的布局都变成了填空题。
如果你喜欢这篇文章,欢迎点赞、收藏、分享。明天我们将进入CSS另一个重要话题——响应式设计与移动端适配,教你如何一套代码搞定手机、平板、电脑。
明日预告:响应式设计的核心:媒体查询、流式布局、移动端适配,从零构建一个全端兼容的页面。