在前端开发中,布局是页面呈现的骨架。从早期的 table 布局、float 布局,到如今的 Flexbox 和 CSS Grid,布局方式经历了翻天覆地的变化。本文将系统性地梳理 Flexbox 和 Grid 的核心概念,并通过实战案例展示如何用它们构建复杂且优雅的响应式页面。
一、Flexbox:一维布局之王
Flexbox(弹性盒子布局)是一个一维布局模型,擅长处理行或列方向上的元素排列。它最大的优势在于灵活处理元素的对齐、分布和自适应空间。
1.1 基本概念
Flex 布局由容器(flex container)和项目(flex item)组成。容器通过 display: flex 声明,内部子元素自动成为弹性项目。
.container {
display: flex;
justify-content: center; /* 主轴对齐 */
align-items: center; /* 交叉轴对齐 */
gap: 16px; /* 项目间距 */
}
.item {
flex: 1; /* 等分剩余空间 */
min-width: 0; /* 防止内容溢出 */
}
1.2 常见布局模式
导航栏布局: Logo 靠左、导航链接居中、操作按钮靠右。这是 Flex 最经典的场景之一。
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 24px;
height: 64px;
}
.navbar .logo { flex-shrink: 0; }
.navbar .links { display: flex; gap: 24px; }
.navbar .actions { flex-shrink: 0; }
垂直居中: Flexbox 解决垂直居中只需两行代码,告别了 margin 负值和 transform hack 时代。
.center-box {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
等高列布局: 传统 CSS 实现等高列需要各种 hack,Flexbox 天然支持。
.columns {
display: flex;
gap: 20px;
}
.columns > div {
flex: 1; /* 所有列自动等高 */
padding: 20px;
background: #fff;
}
1.3 Flex 实用技巧
flex: 1 是 flex-grow: 1; flex-shrink: 1; flex-basis: 0% 的简写。理解这三个属性才能精确控制元素行为:
- flex-grow:空间有剩余时,项目如何放大(默认 0,不放大)
- flex-shrink:空间不足时,项目如何缩小(默认 1,可缩小)
- flex-basis:项目在分配空间前的初始尺寸(默认 auto)
/* 经典的"固定侧边栏 + 自适应内容"布局 */
.sidebar { flex: 0 0 280px; } /* 不放大不缩小,固定 280px */
.main { flex: 1; } /* 占满剩余空间 */
换行与间距: 当项目过多需要换行时,使用 flex-wrap: wrap 配合 gap 属性控制间距。
.card-grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.card-grid > .card {
flex: 1 1 300px; /* 最小宽度 300px,空间够则等分 */
max-width: calc(50% - 10px); /* 限制最大宽度 */
}
二、CSS Grid:二维布局的终极方案
如果说 Flexbox 擅长一维(行或列),那么 CSS Grid 就是二维布局的王者——它可以同时控制行和列。
2.1 基本概念
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 三列等宽 */
grid-template-rows: auto; /* 行高自适应内容 */
gap: 24px;
padding: 24px;
}
fr 单位是 Grid 独有的弹性单位,1fr 表示一份可用空间。配合 repeat() 函数可以快速创建网格。
2.2 经典布局案例
圣杯布局: 头部 + 左侧导航 + 主内容区 + 右侧边栏 + 底部。这是 Grid 最擅长的场景:
.holy-grail {
display: grid;
grid-template-columns: 240px 1fr 300px;
grid-template-rows: 64px 1fr 48px;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
/* 响应式:小屏变单列 */
@media (max-width: 768px) {
.holy-grail {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"main"
"sidebar"
"aside"
"footer";
}
}
自适应网格: 使用 auto-fit / auto-fill + minmax() 实现无需媒体查询的响应式布局:
.responsive-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 24px;
}
这段代码的魔法在于:每列最小 280px,空间够则放更多列,空间不够自动换行。一个属性搞定响应式,不需要写任何 @media 查询。
2.3 Grid 高级技巧
跨行跨列: 让某个元素跨越多行或多列:
.featured {
grid-column: span 2; /* 横跨两列 */
grid-row: span 2; /* 纵跨两行 */
}
/* 或者精确指定位置 */
.hero-card {
grid-column: 1 / -1; /* 从第1条线到最后一条线,占满整行 */
}
子网格(Subgrid): CSS Subgrid 允许子元素继承父网格的轨道定义,实现嵌套布局的对齐:
.card {
display: grid;
grid-template-columns: subgrid;
grid-column: span 3; /* 继承父网格的 3 列轨道 */
}
.card .title { grid-column: 1; }
.card .body { grid-column: 2; }
.card .action { grid-column: 3; }
/* 子元素与父网格完美对齐 */
隐式网格与自动放置: 未显式定位的项目会按自动放置规则排列。通过 grid-auto-flow: dense 可以让 Grid 自动填充空隙:
.masonry-like {
display: grid;
grid-auto-flow: dense; /* 密集排列,减少空隙 */
grid-template-columns: repeat(4, 1fr);
}
.tall-item { grid-row: span 2; } /* 高元素占两行,其他元素自动填充空位 */
三、Flexbox vs Grid:如何选择?
这是一个常见问题。简单来说:
- Flexbox 适合一维布局:导航栏、工具栏、卡片内部排列、表单
- Grid 适合二维布局:页面整体布局、卡片网格、仪表盘、图片墙
- 组合使用:Grid 做大框架,Flexbox 做局部排列——这是最佳实践
/* 实际项目中的典型组合 */
.page-layout {
display: grid; /* 二维:整体页面结构 */
grid-template-columns: 260px 1fr;
grid-template-rows: 64px 1fr auto;
grid-template-areas:
"nav header"
"nav main"
"nav footer";
min-height: 100vh;
}
.page-header {
display: flex; /* 一维:头部内部排列 */
justify-content: space-between;
align-items: center;
}
.card-list {
display: grid; /* 二维:卡片网格 */
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 20px;
}
.card-body {
display: flex; /* 一维:卡片内容 */
flex-direction: column;
gap: 12px;
}
四、响应式断点策略
响应式布局不仅是技术问题,更是设计决策。以下是经过大量实践验证的断点策略:
/* Mobile First 策略(推荐) */
.container { max-width: 100%; padding: 0 16px; }
/* 平板 ≥ 768px */
@media (min-width: 768px) {
.container { max-width: 720px; padding: 0 24px; }
.grid { grid-template-columns: repeat(2, 1fr); }
}
/* 桌面 ≥ 1024px */
@media (min-width: 1024px) {
.container { max-width: 960px; }
.grid { grid-template-columns: repeat(3, 1fr); }
}
/* 大屏 ≥ 1280px */
@media (min-width: 1280px) {
.container { max-width: 1200px; }
.grid { grid-template-columns: repeat(4, 1fr); }
}
/* 超大屏 ≥ 1536px */
@media (min-width: 1536px) {
.container { max-width: 1400px; }
}
使用 min-width 而非 max-width 的 Mobile First 策略有几个好处:基础样式面向移动端,CSS 更简洁,性能更好(移动端不需要解析不匹配的 max-width 规则)。
五、实战:构建一个响应式博客首页
综合运用 Grid 和 Flexbox,构建一个完整的博客首页布局:
/* 整体页面结构 - Grid */
.blog-page {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto auto 1fr auto;
min-height: 100vh;
}
@media (min-width: 1024px) {
.blog-page {
grid-template-columns: 1fr 300px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"main sidebar"
"footer footer";
}
}
/* 导航栏 - Flex */
.nav {
display: flex;
justify-content: space-between;
align-items: center;
height: 64px;
}
/* 文章卡片网格 - Grid */
.article-grid {
display: grid;
grid-template-columns: 1fr;
gap: 24px;
}
@media (min-width: 768px) {
.article-grid { grid-template-columns: repeat(2, 1fr); }
}
/* 侧边栏 - Flex 纵向排列 */
.sidebar {
display: flex;
flex-direction: column;
gap: 24px;
}
/* 卡片内部 - Flex */
.article-card {
display: flex;
flex-direction: column;
gap: 12px;
}
.article-card .meta {
display: flex;
align-items: center;
gap: 12px;
}
六、性能与最佳实践
现代 CSS 布局性能已经非常优秀,但仍有一些值得注意的实践:
- 避免
position: absolute过度使用: Grid 和 Flexbox 大部分场景可以替代绝对定位 gap代替 margin: gap 属性比 margin 紧凑,不会产生边距折叠问题min-width: 0防溢出: Flex 项目默认 min-width: auto,内容可能撑破容器auto-fitvsauto-fill: auto-fit 会折叠空轨道,auto-fill 保留空轨道- content-box vs border-box: 全局设置
box-sizing: border-box避免尺寸计算问题
/* 推荐的全局重置 */
*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Flex 防溢出 */
.flex-item {
flex: 1;
min-width: 0; /* 允许项目缩小到内容宽度以下 */
}
Flexbox 和 Grid 的出现彻底改变了 CSS 布局的方式。Flexbox 简化了单一方向的排列,Grid 统治了二维空间。在实际项目中,两者配合使用是最强大的方案——Grid 搭建骨架,Flexbox 调整细节。掌握了它们,你就能轻松应对几乎所有的布局需求。