CSS Flexbox 弹性布局

Flexbox(弹性盒子布局)是 CSS 一维布局的核心方案。它能让你轻松地在一行或一列中排列元素,并自动处理对齐、分布和空间分配。

启用 Flexbox

将容器的 display 设为 flex

css
.container {
  display: flex;
}

容器成为 flex 容器,它的直接子元素成为 flex 子项。两条轴线定义了 flex 的世界:

  • 主轴(main axis)——子项排列的方向
  • 交叉轴(cross axis)——与主轴垂直的方向
html
<div class="container">
  <div class="item">A</div>
  <div class="item">B</div>
  <div class="item">C</div>
</div>

容器属性

这些属性写在 flex 容器上,控制所有子项的布局行为。

flex-direction — 主轴方向

css
.container {
  display: flex;
  flex-direction: row;            /* 默认:左→右 */
  flex-direction: row-reverse;    /* 右→左 */
  flex-direction: column;         /* 上→下 */
  flex-direction: column-reverse; /* 下→上 */
}

justify-content — 主轴对齐

控制子项在主轴上的分布方式:

效果
flex-start靠主轴起点(默认)
flex-end靠主轴终点
center居中
space-between两端对齐,中间均匀分布
space-around每个子项两侧有相等间距
space-evenly所有间距相等(包括两端)
css
.navbar {
  display: flex;
  justify-content: space-between;
}
/* Logo 在最左,导航链接在最右 */

align-items — 交叉轴对齐

控制子项在交叉轴上的对齐方式:

效果
stretch拉伸填满容器(默认)
flex-start靠交叉轴起点
flex-end靠交叉轴终点
center居中
baseline文本基线对齐
css
/* 垂直居中(单行) */
.vertical-center {
  display: flex;
  align-items: center;
}

flex-wrap — 换行

默认情况下 flex 子项不换行,全部挤在一行:

css
.container {
  display: flex;
  flex-wrap: nowrap;       /* 不换行(默认) */
  flex-wrap: wrap;         /* 允许换行 */
  flex-wrap: wrap-reverse; /* 换行,但交叉轴反向 */
}

align-content — 多行对齐

flex-wrap: wrap 且有多行时,控制行与行之间在交叉轴上的分布:

css
.container {
  display: flex;
  flex-wrap: wrap;
  align-content: space-between; /* 行之间均匀分布 */
}

取值与 justify-content 相同。如果只有一行,align-content 无效。

gap — 子项间距

css
.container {
  display: flex;
  gap: 1rem;          /* 行间距和列间距相同 */
  gap: 1rem 2rem;     /* 行间距 列间距 */
  row-gap: 1rem;      /* 仅行间距 */
  column-gap: 2rem;   /* 仅列间距 */
}

gap 是管理间距的现代方案,取代了以往用 margin + :not(:last-child) 的技巧。它只在子项之间产生间距,不会在容器边缘产生多余空白。

子项属性

这些属性写在 flex 子项上,控制各自的行为。

flex — 伸缩简写

flex 是三个属性的简写:flex-growflex-shrinkflex-basis

css
.item {
  flex: 1;            /* flex-grow: 1; flex-shrink: 1; flex-basis: 0 */
  flex: 1 0 200px;    /* grow: 1; shrink: 0; basis: 200px */
  flex: auto;         /* 1 1 auto — 按内容比例分配 */
  flex: none;         /* 0 0 auto — 不伸缩,保持固有尺寸 */
}

flex-grow — 放大比例

当容器有剩余空间时,子项以何种比例瓜分:

css
.item-1 { flex-grow: 1; } /* 占 1 份 */
.item-2 { flex-grow: 2; } /* 占 2 份(两倍宽) */
.item-3 { flex-grow: 0; } /* 不放大(默认) */

flex-shrink — 缩小比例

当容器空间不足时,子项以何种比例收缩:

css
.item { flex-shrink: 0; } /* 禁止收缩(保持尺寸) */

flex-basis — 初始尺寸

子项在分配剩余空间之前的初始大小:

css
.sidebar { flex-basis: 250px; }          /* 初始 250px */
.content { flex: 1; }                    /* 占据剩余空间 */
.half { flex-basis: 50%; }

align-self — 独立交叉轴对齐

覆盖容器的 align-items,对单个子项设置:

css
.special-item {
  align-self: flex-start; /* 自己靠顶部,其他子项可能居中 */
}

order — 排列顺序

改变子项的视觉顺序(不影响 HTML 结构):

css
.item-1 { order: 3; } /* 排在第 3 个 */
.item-2 { order: 1; } /* 排在第 1 个 */
.item-3 { order: 2; } /* 排在第 2 个 */

默认所有子项 order: 0,从小到大排列。

order 只改变视觉顺序,不改变 DOM 结构和键盘 Tab 导航顺序。如果你的布局逻辑依赖于 order,可能意味着 HTML 结构本身需要重新审视。

经典布局模式

两栏布局(侧边栏 + 内容)

css
.layout {
  display: flex;
}
.sidebar {
  width: 250px;
  flex-shrink: 0; /* 侧边栏不会被压缩 */
}
.content {
  flex: 1; /* 占据剩余空间 */
}
html
<div class="layout">
  <aside class="sidebar">侧边栏</aside>
  <main class="content">主要内容</main>
</div>

三栏布局(圣杯/双飞翼)

css
.three-col {
  display: flex;
  gap: 2rem;
}
.side-left { width: 200px; }
.content { flex: 1; }
.side-right { width: 200px; }

居中(水平+垂直)

css
.center {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 300px;
}

导航栏(Logo 左 + 菜单右)

css
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 2rem;
  height: 64px;
}
.nav-menu {
  display: flex;
  gap: 1.5rem;
}

自适应卡片网格

css
.card-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}
.card {
  flex: 1 1 300px; /* 最小 300px,空间充裕时等分 */
  max-width: 400px;
}

Flexbox 擅长一维布局(一行或一列)。如果你需要对行和列同时进行精确控制(如一整页的二维网格),应该使用 CSS Grid