上周接了个后台管理系统的活,产品甩过来一张布局截图:左侧导航固定宽度,顶部通栏,中间内容区分三栏,底部还要个跨满整行的状态栏。我当时脑子里第一反应是------这用 Flex 得嵌套多少层 div?后来切到 CSS Grid,代码量直接砍了一半。
先搞清楚 Grid 到底在干嘛
很多人一听到 Grid 就觉得是"高级 Flexbox",其实它俩解决的问题不一样。Flexbox 是一维布局,一次只能处理一行或一列。Grid 是二维布局,行和列同时控制。
你可以把 Grid 想象成 Excel 表格------你定义好几行几列,然后往格子里放东西,想跨行跨行,想跨列跨列。
先看个最基础的例子,三列等宽布局:
css
.container {
display: grid; /* 开启 Grid 布局 */
grid-template-columns: 1fr 1fr 1fr; /* 三列等分,1fr 表示一份空间 */
gap: 16px; /* 行列间距统一 16px */
}
fr 这个单位是 Grid 的核心。它代表"可用空间的一份",你写 1fr 2fr 就是第二列占第一列的两倍宽。比百分比好使多了,不用自己算剩余空间。
repeat() 函数可以简化重复写法,上面三列等宽等价于:
css
.container {
grid-template-columns: repeat(3, 1fr); /* 重复3次,每次1fr */
}
后台管理系统布局实战
回到开头那个需求,用 Grid 来搭后台管理系统的整体骨架,代码其实很直观。
先写个"朴素版",很多人一开始会这么干:
css
/* 朴素写法:手动算宽度,改一个数字全局崩 */
.layout {
display: grid;
grid-template-columns: 240px 1fr; /* 侧边栏240px,内容区自适应 */
grid-template-rows: 60px 1fr 40px; /* 顶部60px,内容区撑满,底部40px */
height: 100vh; /* 撑满整个视口 */
}
这个写法能跑,但问题在于------如果你要给某个区域命名、调整顺序,全靠 grid-row 和 grid-column 的数值去定位,一改就乱。
更好的做法是用 grid-template-areas,直接"画"出布局:
css
.layout {
display: grid;
/* 用字符串"画"出布局结构,每个单词对应一个区域名 */
grid-template-areas:
"sidebar header" /* 第一行:侧边栏 + 顶部导航 */
"sidebar main" /* 第二行:侧边栏 + 内容区 */
"sidebar footer"; /* 第三行:侧边栏 + 底部状态栏 */
grid-template-columns: 240px 1fr; /* 侧边栏固定240px,右侧自适应 */
grid-template-rows: 60px 1fr 40px; /* 顶60 中自适应 底40 */
height: 100vh;
}
/* 每个子元素直接声明自己属于哪个区域,一目了然 */
.sidebar { grid-area: sidebar; } /* 侧边栏 */
.header { grid-area: header; } /* 顶部导航 */
.main { grid-area: main; } /* 内容区 */
.footer { grid-area: footer; } /* 底部状态栏 */
看到区别了吧?grid-template-areas 就像在代码里画了个布局示意图,谁在哪、跨不跨行,一眼就明白。后续要调整布局,改字符串就行,子元素的 CSS 完全不用动。
如果内容区还要再细分,比如左侧列表 + 右侧详情,直接在 .main 里再嵌套一个 Grid:
css
.main {
display: grid;
grid-template-columns: 1fr 1fr; /* 内容区左右各占一半 */
gap: 12px; /* 中间留12px间距 */
padding: 16px; /* 内边距 */
}
Grid 和 Flexbox 到底怎么选
这个问题我被问了不下十次。简单说:一维用 Flex,二维用 Grid。但实际项目里没这么非黑即白。
下面是我总结的一个对照表,基本能覆盖大部分选型场景:
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 导航栏内部元素排列 | Flexbox | 单行排列,flex 的 space-between 就够了 |
| 页面整体骨架布局 | Grid | 需要同时控制行和列 |
| 卡片列表(等宽自适应) | Grid | repeat(auto-fill, minmax(280px, 1fr)) 一行搞定 |
| 表单 label + input 对齐 | Grid | 两列网格天然对齐,不用算 label 宽度 |
| 居中对齐一个元素 | Flexbox | justify-content + align-items 最简洁 |
| 不规则瀑布流 | 都不太行 | 考虑 Masonry 布局或 JS 方案 |
卡片列表那个写法值得单独说一下:
css
.card-list {
display: grid;
/* 每列最少280px,容器能放几列就放几列 */
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px; /* 卡片间距 */
}
auto-fill 的意思就是"自动填列"------容器够宽就塞新列,不够就换行。配合 minmax(280px, 1fr),每张卡片最小 280px,最大撑满剩余空间。不用写一行媒体查询就能实现响应式。
有个容易踩的坑:auto-fill 和 auto-fit 看着差不多,行为不一样。auto-fill 会保留空列(右边可能留白),auto-fit 会把空列折叠掉让现有列撑满。大多数场景下 auto-fit 更符合预期。
几个容易忽略的实用技巧
minmax() 替代媒体查询做自适应
css
.container {
grid-template-columns: repeat(3, minmax(200px, 1fr)); /* 每列最小200px */
}
当容器宽度不够放三列 200px 时,Grid 会自动换行,不需要额外写 @media。
place-items 一行搞定居中
css
.container {
display: grid;
height: 100vh;
place-items: center; /* 水平垂直同时居中,等价于 justify + align */
}
这比 Flexbox 的 justify-content: center; align-items: center; 还少写一行。
子元素自己控制跨列
不需要改容器定义,子元素自己声明就行:
css
.featured-card {
grid-column: span 2; /* 这个卡片横跨两列 */
}
.full-width-banner {
grid-column: 1 / -1; /* 从第一列到最后一列,跨满整行 */
}
span 2 是"往右跨两列",1 / -1 是"从第一条网格线到最后一条",两种写法看场景选。
最后
用了大半年 Grid 做后台项目,几点感受:
- Grid 做页面骨架,Flex 做组件内部排列,两者配合用才是正解
grid-template-areas是后台布局的杀手锏,可读性拉满repeat(auto-fit, minmax(...))一行代码搞定响应式卡片列表- 别死磕"用 Grid 还是 Flex",实际项目里嵌套着用才是常态
- Grid 的浏览器兼容性已经没问题了,IE 不管了,放心用
你们项目里 Grid 用得多还是 Flex 用得多?评论区聊聊。