CSS Flexbox 与 Grid:何时使用哪个
· 12分钟阅读
目录
在 CSS Flexbox 和 Grid 之间做选择可能让人感到不知所措,尤其是当两者似乎都能解决相同的布局问题时。事实上,它们是为不同目的而设计的,理解它们的优势将使你成为更高效的开发者。
本指南详细介绍了关于 Flexbox 和 Grid 你需要知道的一切,从核心概念到实际应用。读完后,你将确切知道在任何布局场景中该使用哪个工具。
Flexbox 基础(一维布局)
Flexbox 专为一维布局设计——在单行或单列中排列项目。它擅长沿一个轴分配空间和对齐项目,非常适合导航栏、按钮组和单向流动的内容。
核心概念
每个 Flexbox 布局都有一个弹性容器(父元素)和弹性项目(子元素)。容器控制其项目的方向、换行和对齐:
/* 弹性容器 */
.container {
display: flex;
flex-direction: row; /* row | row-reverse | column | column-reverse */
justify-content: center; /* 主轴对齐 */
align-items: center; /* 交叉轴对齐 */
gap: 1rem; /* 项目之间的间距 */
flex-wrap: wrap; /* 允许项目换行 */
}
/* 弹性项目 */
.item {
flex: 1; /* 增长以填充可用空间 */
/* 简写形式: flex-grow: 1; flex-shrink: 1; flex-basis: 0; */
}
.item-fixed {
flex: 0 0 200px; /* 不增长,不收缩,200px 宽 */
}
理解主轴和交叉轴
掌握 Flexbox 的关键是理解它的两个轴。主轴沿着 flex-direction 设置的方向运行(row 为水平,column 为垂直)。交叉轴垂直于主轴。
这个轴系统决定了哪些属性控制哪些维度。justify-content 始终作用于主轴,而 align-items 作用于交叉轴。
对齐属性
/* 主轴(row 方向为水平) */
.container {
justify-content: flex-start; /* 默认:项目靠起点对齐 */
justify-content: flex-end; /* 项目靠终点对齐 */
justify-content: center; /* 项目居中 */
justify-content: space-between;/* 项目之间等距 */
justify-content: space-around; /* 项目周围等距 */
justify-content: space-evenly; /* 所有地方等距 */
}
/* 交叉轴(row 方向为垂直) */
.container {
align-items: stretch; /* 默认:拉伸填充容器 */
align-items: flex-start; /* 顶部对齐 */
align-items: flex-end; /* 底部对齐 */
align-items: center; /* 垂直居中 */
align-items: baseline; /* 文本基线对齐 */
}
Flex 属性详解
flex 属性是三个属性的简写:flex-grow、flex-shrink 和 flex-basis。单独理解这些属性有助于你编写更精确的布局。
- flex-grow: 项目相对于其他项目应该增长多少(默认:0)
- flex-shrink: 空间有限时项目应该收缩多少(默认:1)
- flex-basis: 增长或收缩前的初始大小(默认:auto)
.item-grow {
flex: 1; /* 等同于: 1 1 0% */
}
.item-fixed {
flex: 0 0 200px; /* 不增长或收缩,保持 200px */
}
.item-shrink {
flex: 0 1 auto; /* 不增长,但需要时可以收缩 */
}
专业提示: 当你希望项目平均分配空间时使用 flex: 1,当你希望项目保持其自然大小而不增长或收缩时使用 flex: 0 0 auto。
Grid 基础(二维布局)
CSS Grid 专为二维布局而构建——同时控制行和列。它是页面级布局、卡片网格以及任何需要精确控制两个维度的设计的首选。
核心概念
Grid 布局由网格容器和网格项目组成。与 Flexbox 不同,Grid 允许你定义显式轨道(行和列)并将项目放置在该结构中的任何位置:
/* 网格容器 */
.container {
display: grid;
grid-template-columns: 200px 1fr 1fr; /* 3列 */
grid-template-rows: auto 1fr auto; /* 3行 */
gap: 1rem; /* 单元格之间的间距 */
grid-auto-flow: row; /* 自动放置项目的流动方式 */
}
/* 网格项目 */
.item {
grid-column: 1 / 3; /* 从列线1跨越到3 */
grid-row: 1 / 2; /* 占据第一行 */
}
.item-area {
grid-area: header; /* 放置在命名区域 */
}
理解网格线和轨道
Grid 在轨道之间创建编号线。一个3列网格有4条垂直线(1、2、3、4)。项目通过指定它们跨越的线来放置。
轨道是线之间的空间——你实际的列和行。你可以使用固定单位(px)、弹性单位(fr)或基于内容的大小(auto、min-content、max-content)来调整它们的大小。
FR 单位
fr 单位是 Grid 的超能力。它代表可用空间的一部分,按比例在轨道之间分配:
.container {
grid-template-columns: 1fr 2fr 1fr; /* 中间列获得2倍空间 */
grid-template-columns: 200px 1fr; /* 固定侧边栏,弹性内容 */
grid-template-columns: repeat(3, 1fr); /* 三个相等的列 */
}
命名网格区域
Grid 的模板区域功能允许你使用类似 ASCII 艺术的语法创建布局,使复杂布局易于阅读:
.container {
display: grid;
grid-template-areas:
"header header header"
"sidebar content content"
"footer footer footer";
grid-template-columns: 200px 1fr 1fr;
grid-template-rows: auto 1fr auto;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer { grid-area: footer; }
自动放置和网格自动流
Grid 可以自动放置你没有明确定位的项目。grid-auto-flow 属性控制项目是先填充行(默认)还是先填充列:
.container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-flow: dense; /* 用较小的项目填充空隙 */
}
专业提示: 对于类似瀑布流的布局,使用 grid-auto-flow: dense 来填充空隙,但要注意这可能会改变项目的视觉顺序,可能影响可访问性。
并排比较
让我们在关键维度上比较 Flexbox 和 Grid,以理解它们的根本区别:
| 特性 | Flexbox | Grid |
|---|---|---|
| 维度 | 一维(行或列) | 二维(行和列) |
| 内容驱动 | 是 - 项目控制其大小 | 否 - 容器定义结构 |
| 布局方向 | 一次一个轴 | 同时两个轴 |
| 项目放置 | 顺序(源顺序) | 可以显式定位 |
| 对齐 | 单轴上强大 | 两个轴上都强大 |
| 间距支持 | 是(现代浏览器) | 是(从一开始) |
| 最适合 | 组件、导航、工具栏 | 页面布局、卡片网格、仪表板 |
| 学习曲线 | 中等 | 初期较陡 |
概念差异
根本区别在于控制。Flexbox 是由内而外——项目根据其内容大小影响布局。Grid 是由外而内——你首先定义结构,然后将内容放入其中。
把 Flexbox 想象成一把灵活的尺子,可以根据你测量的内容进行调整。Grid 更像是方格纸,你预先决定结构。
| 场景 | Flexbox 方法 | Grid 方法 |
|---|---|---|
| 导航栏 | 自然适配 - 项目排成一行 | 过度 - 结构太多 |
| 卡片网格 | 可能但换行笨拙 | 完美 - 显式的行和列 |
| 表单布局 | 适合简单表单 | 更适合复杂的多列表单 |
| 页面布局 | 需要嵌套多个容器 | 单个容器就能处理 |
| 内容居中 | 出色 - 简单直观 | 同样出色 - place-items: center |
何时使用 Flexbox
Flexbox 在内容沿单一方向流动且项目需要适应可用空间的场景中表现出色。以下是 Flexbox 是最佳选择的情况:
导航栏和菜单
导航组件是 Flexbox 的典型应用。项目自然地排成一行,你通常希望它们均匀分配空间或对齐到相对的两端:
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
}
.nav-links {
display: flex;
gap: 2rem;
list-style: none;
}
按钮组和工具栏
当你有一组应该并排放置的按钮或工具时,Flexbox 完美地处理间距和对齐:
.button-group {
display: flex;
gap: 0.5rem;
}
.toolbar {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 1rem;
}
媒体对象
经典的媒体对象模式(一侧是图像,另一侧是内容)用 Flexbox 非常简单:
.media {
display: flex;
gap: 1rem;
}
.media-image {
flex: 0 0 100px; /* 固定宽度图像 */
}
.media-content {
flex: 1; /* 内容占据剩余空间 */
}
表单控件
标签、输入框和按钮排成一行的输入组非常适合 Flexbox:
.input-group {
display: flex;
gap: 0.5rem;
}
.input-group input {
flex: 1; /* 输入框增长以填充空间 */
}
.input-group button {
flex: 0 0 auto; /* 按钮保持自然大小 */
}