返回首页

CSS 现代布局:Flexbox 与 Grid 怎么选、怎么配合

Flexbox 是一维排布的利器,Grid 是二维布局的标准答案。这篇讲清两者的核心模型、各自的适用边界,以及在真实页面里如何把它们组合起来用。

30 约 5 分钟 · 4838 字 前端

写布局时最常见的纠结是:这块该用 Flexbox 还是 Grid?

很多人凭手感选,结果要么用 Flex 硬凑二维网格写得很别扭,要么用 Grid 排一行按钮显得小题大做。其实它们的分工有一条很清晰的界线。

一句话区分

  • Flexbox 是一维布局:一次只管一个方向(一行,或者一列)
  • Grid 是二维布局:同时管行和列

判断方法:如果你脑子里想的是"把这些东西排成一排/一列",用 Flex;如果你想的是"我要一个几行几列的结构",用 Grid。

Flexbox 的核心模型

Flexbox 围绕**主轴(main axis)交叉轴(cross axis)**展开。

.container {
  display: flex;
  flex-direction: row;        /* 主轴方向:row(默认横向)| column(纵向) */
  justify-content: center;    /* 主轴上如何对齐 */
  align-items: center;        /* 交叉轴上如何对齐 */
  gap: 12px;                  /* 子项之间的间距 */
}

记住两个对齐属性的分工:

  • justify-content主轴(主轴是 row 时就是水平方向)
  • align-items交叉轴(与主轴垂直的方向)

这也是为什么"水平垂直居中"一行就能搞定:

.center {
  display: flex;
  justify-content: center;
  align-items: center;
}

flex 子项的伸缩

Flex 真正强大的地方是子项能按比例伸缩,核心是 flex 这个简写:

.item {
  flex: 1;   /* = flex-grow:1  flex-shrink:1  flex-basis:0 */
}

flex 由三部分组成:

  • flex-grow:剩余空间如何放大分配(0 表示不放大)
  • flex-shrink:空间不够时如何缩小(0 表示不缩小)
  • flex-basis:分配前的基准尺寸

常见用法:

/* 三栏等宽 */
.col { flex: 1; }

/* 侧栏固定 240px,主区占满剩余 */
.sidebar { flex: 0 0 240px; }
.main { flex: 1; }

flex: 0 0 240px 的意思是"不放大、不缩小、基准 240px",也就是一个固定宽度但又参与 Flex 布局的盒子。

Grid 的核心模型

Grid 让你直接声明一个网格结构。

.container {
  display: grid;
  grid-template-columns: 200px 1fr 1fr;  /* 三列:固定 + 两个等分 */
  grid-template-rows: auto 1fr auto;     /* 三行 */
  gap: 16px;
}

最关键的新单位是 fr(fraction,剩余空间的份数):

grid-template-columns: 1fr 2fr;  /* 第二列宽度是第一列的两倍 */

repeat 和 minmax

列很多时用 repeat 简写:

grid-template-columns: repeat(3, 1fr);  /* 等价于 1fr 1fr 1fr */

minmax(最小值, 最大值) 限定尺寸范围,常用于响应式:

grid-template-columns: repeat(3, minmax(0, 1fr));

这里的 minmax(0, 1fr) 是个实用技巧:它能防止内容(比如一段长文本或图片)把列撑爆,保证三列真正等宽。

自适应列数:auto-fill / auto-fit

不写死列数,让网格根据容器宽度自动决定放几列:

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}

这一行的含义是:每列至少 220px,容器能放下几列就放几列,放不下自动换行。一个纯 CSS、不写媒体查询的响应式卡片墙就完成了。

auto-fitauto-fill 很像,区别在于列不满时:auto-fit 会让现有列拉伸填满整行,auto-fill 会保留空列。想让卡片铺满一行通常用 auto-fit

用区域命名做整页布局

Grid 还能用命名区域,非常适合整页骨架:

.layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: 64px 1fr 48px;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  min-height: 100vh;
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }

布局结构在 CSS 里一目了然,比一堆嵌套 div 直观得多。

怎么选:一维用 Flex,二维用 Grid

回到最初的问题,给几个具体判断:

用 Flexbox 的场景:

  • 一行导航/按钮组
  • 一个组件内部的横向排布(图标 + 文字)
  • 需要子项按比例伸缩(侧栏固定 + 主区自适应)
  • 垂直居中一个元素

用 Grid 的场景:

  • 整页布局骨架(头部/侧栏/主体/底部)
  • 卡片墙、图片画廊
  • 表格状的二维结构
  • 需要精确控制行列对齐的复杂布局

一个经验法则:只关心"一排怎么排"用 Flex,关心"行和列同时怎么对齐"用 Grid。

它们不是二选一,而是配合

真实页面里,最常见的是 Grid 管大骨架,Flex 管局部

比如一个典型的后台页:用 Grid 划分整体区域,每个区域内部用 Flex 排列具体内容。

/* 外层:Grid 划分页面 */
.page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: 64px 1fr;
  grid-template-areas:
    "sidebar header"
    "sidebar main";
  height: 100vh;
}

/* 顶栏内部:Flex 排 logo、搜索框、头像 */
.header {
  grid-area: header;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
}

/* 卡片区:Grid 自适应铺卡片 */
.main {
  grid-area: main;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px;
  padding: 16px;
  overflow: auto;
}

/* 单张卡片内部:Flex 纵向排内容 */
.card {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

这套"Grid 搭骨架、Flex 填血肉"的组合,几乎能覆盖绝大多数页面。

几个实用细节

1. gap 两者都能用

以前 Flex 要靠 margin 凑间距,很麻烦。现在 gap 在 Flex 和 Grid 里都支持,优先用它。

2. 别忘了 min-width: 0

Flex 子项默认 min-width: auto,内容过长时不会缩小,会撑破布局。需要省略号或换行时,常常要给子项加 min-width: 0:

.flex-item {
  flex: 1;
  min-width: 0;       /* 允许收缩,配合下面的省略号 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Grid 里对应的是前面提过的 minmax(0, 1fr),同样是为了允许收缩。

3. place-items 简写居中

Grid 里垂直水平居中可以一行:

.center {
  display: grid;
  place-items: center;
}

常见坑

第一,用 Flex 硬排二维网格。子项换行后上下两行对不齐,得靠固定宽度凑。这种情况就该用 Grid。

第二,Grid 列被内容撑爆。忘了 minmax(0, 1fr),一张大图或一段不换行的长文本就把"等宽"破坏了。

第三,Flex 子项不收缩导致溢出。没加 min-width: 0,长文本撑破容器还不出省略号。

第四,过度嵌套。能用一层 Grid 区域解决的,别套五六层 div。命名区域往往比嵌套更清晰。

总结

  • Flexbox 管一维:一行或一列的排布、对齐、按比例伸缩
  • Grid 管二维:行列同时控制,适合整页骨架和卡片墙
  • 选择标准:只排一排用 Flex,要行列结构用 Grid
  • 实战里两者配合最常见:Grid 搭大骨架,Flex 填内部细节
  • 记牢两个救命技巧:Flex 子项加 min-width: 0、Grid 列用 minmax(0, 1fr),能解决大半溢出问题

把这两套模型吃透,几乎所有页面布局都能不靠 float、不靠绝对定位,干净利落地写出来。