跳到主要内容

CSS Flexbox 布局

Flexbox(弹性盒子布局)是 CSS3 引入的一种一维布局模式,专门用于在行或列中分配空间和对齐元素。它解决了传统布局方式(如 float、inline-block)的诸多痛点,成为现代 CSS 布局的基础技术之一。

为什么需要 Flexbox

在 Flexbox 出现之前,实现以下布局需求并不容易:

  • 子元素等宽分布
  • 子元素垂直居中
  • 子元素高度自动对齐
  • 改变子元素的显示顺序
  • 响应式地调整布局

传统方案需要各种技巧,比如垂直居中需要绝对定位加 transform,等高列需要设置大 padding 加负 margin。Flexbox 让这些需求变得简单直接。

Flexbox 基本概念

Flexbox 涉及两个核心概念:

Flex 容器:设置了 display: flexdisplay: inline-flex 的元素,它成为弹性容器,其直接子元素成为弹性项目。

Flex 项目:Flex 容器的直接子元素,它们会按照弹性布局规则排列。

<div class="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
.container {
display: flex; /* 成为 flex 容器 */
}

.item {
/* 直接子元素成为 flex 项目 */
}

Flexbox 布局基于两条轴:主轴(main axis)和交叉轴(cross axis)。默认情况下,主轴是水平方向(从左到右),交叉轴是垂直方向(从上到下)。

容器属性

flex-direction 主轴方向

flex-direction 决定主轴的方向,即项目的排列方向:

.container {
display: flex;
flex-direction: row; /* 默认:水平从左到右 */
}

可选值:

  • row:水平方向,从左到右(默认)
  • row-reverse:水平方向,从右到左
  • column:垂直方向,从上到下
  • column-reverse:垂直方向,从下到上
.horizontal {
flex-direction: row;
}

.vertical {
flex-direction: column;
}

.reverse {
flex-direction: row-reverse;
}

主轴方向决定了后续所有对齐属性的参考方向。

flex-wrap 换行方式

flex-wrap 控制项目是否换行:

.container {
flex-wrap: nowrap; /* 默认:不换行 */
}

可选值:

  • nowrap:不换行,项目会缩小以适应容器(默认)
  • wrap:换行,第一行在上方
  • wrap-reverse:换行,第一行在下方
.no-wrap {
flex-wrap: nowrap; /* 项目可能被压缩 */
}

.wrap {
flex-wrap: wrap; /* 超出时换行 */
}

默认 nowrap 时,如果项目总宽度超过容器,项目会被压缩。设置为 wrap 可以让项目保持原始尺寸,超出时换行显示。

flex-flow 简写

flex-flowflex-directionflex-wrap 的简写:

.container {
flex-flow: row wrap; /* 方向 换行方式 */
}

justify-content 主轴对齐

justify-content 控制项目在主轴上的对齐方式:

.container {
justify-content: flex-start; /* 默认:起点对齐 */
}

可选值:

/* 起点对齐 */
flex-start { justify-content: flex-start; }

/* 终点对齐 */
.flex-end { justify-content: flex-end; }

/* 居中对齐 */
.center { justify-content: center; }

/* 两端对齐,项目间隔相等 */
.space-between { justify-content: space-between; }

/* 项目两侧间隔相等 */
.space-around { justify-content: space-around; }

/* 所有间隔完全相等 */
.space-evenly { justify-content: space-evenly; }

space-between 让第一个项目贴起点,最后一个项目贴终点,中间项目均匀分布。space-around 给每个项目两侧相同的间隔,导致两端间隔是中间间隔的一半。space-evenly 让所有间隔完全相等。

align-items 交叉轴对齐

align-items 控制项目在交叉轴上的对齐方式:

.container {
align-items: stretch; /* 默认:拉伸填满 */
}

可选值:

/* 拉伸填满容器高度(默认) */
.stretch { align-items: stretch; }

/* 起点对齐 */
.flex-start { align-items: flex-start; }

/* 终点对齐 */
.flex-end { align-items: flex-end; }

/* 居中对齐 */
.center { align-items: center; }

/* 基线对齐 */
.baseline { align-items: baseline; }

stretch 是默认值,项目会拉伸到容器高度(如果没有设置高度)。center 是实现垂直居中的关键,只需设置 align-items: center

align-content 多行对齐

align-content 控制多行项目在交叉轴上的对齐方式,仅在 flex-wrap: wrap 时生效:

.container {
flex-wrap: wrap;
align-content: stretch; /* 默认 */
}

可选值与 justify-content 类似:

.stretch { align-content: stretch; }
.flex-start { align-content: flex-start; }
.flex-end { align-content: flex-end; }
.center { align-content: center; }
.space-between { align-content: space-between; }
.space-around { align-content: space-around; }

gap 项目间距

gap 属性设置项目之间的间距,不受对齐方式影响:

.container {
display: flex;
gap: 20px; /* 统一间距 */
gap: 20px 10px; /* 行间距 列间距 */
}

.grid-like {
display: flex;
flex-wrap: wrap;
gap: 20px;
}

gap 比 margin 更方便,因为它不会在容器边缘产生多余间距。

项目属性

flex-grow 放大比例

flex-grow 定义项目的放大比例,决定如何分配剩余空间:

.item {
flex-grow: 0; /* 默认:不放大 */
}
/* 所有项目平分剩余空间 */
.equal .item {
flex-grow: 1;
}

/* 第一个项目占两倍空间 */
.unequal .item:nth-child(1) {
flex-grow: 2;
}
.unequal .item:nth-child(2) {
flex-grow: 1;
}

当容器有剩余空间时,项目按 flex-grow 比例分配这些空间。flex-grow: 1 的项目比 flex-grow: 0 的项目更宽,但具体宽度取决于剩余空间的计算。

flex-shrink 缩小比例

flex-shrink 定义项目的缩小比例,决定空间不足时如何收缩:

.item {
flex-shrink: 1; /* 默认:可缩小 */
}
/* 不允许缩小 */
.no-shrink {
flex-shrink: 0;
}

/* 缩小比例不同 */
.item:nth-child(1) {
flex-shrink: 2; /* 缩小更多 */
}
.item:nth-child(2) {
flex-shrink: 1;
}

默认情况下所有项目都可以缩小。设置 flex-shrink: 0 可以保持项目的原始尺寸不被压缩。

flex-basis 初始大小

flex-basis 定义项目在分配剩余空间之前的初始大小:

.item {
flex-basis: auto; /* 默认:使用项目的 width/height */
}
.basis-fixed {
flex-basis: 200px; /* 固定初始大小 */
}

.basis-auto {
flex-basis: auto; /* 使用 width 值 */
}

.basis-content {
flex-basis: content; /* 根据内容自动计算 */
}

flex-basis 的优先级高于 width。如果设置了 flex-basiswidth 只在 flex-basis: auto 时生效。

flex 简写

flexflex-growflex-shrinkflex-basis 的简写:

.item {
flex: 0 1 auto; /* 默认值:不放大 可缩小 自动大小 */
}

常用简写:

/* 等分空间 */
.equal {
flex: 1; /* 等价于 flex: 1 1 0% */
}

/* 不放大不缩小,固定大小 */
.fixed {
flex: 0 0 200px; /* 固定 200px */
}

/* 可放大不缩小 */
.grow-only {
flex: 1 0 auto;
}

/* 自适应内容 */
.auto {
flex: auto; /* 等价于 flex: 1 1 auto */
}

/* 不伸缩 */
.none {
flex: none; /* 等价于 flex: 0 0 auto */
}

flex: 1 是最常用的简写,表示项目可以等分剩余空间。这与 flex-grow: 1 的区别是,flex: 1 会覆盖 flex-basis 为 0%,确保等分的是全部空间而不仅仅是剩余空间。

align-self 单独对齐

align-self 允许单个项目覆盖容器的 align-items 设置:

.container {
display: flex;
align-items: center;
}

.item:nth-child(2) {
align-self: flex-end; /* 只有第二项在底部 */
}

可选值与 align-items 相同:autoflex-startflex-endcenterbaselinestretch

order 排列顺序

order 改变项目在视觉上的排列顺序:

.item:nth-child(1) { order: 3; }
.item:nth-child(2) { order: 1; }
.item:nth-child(3) { order: 2; }

默认所有项目的 order 为 0。数值小的排在前面,负数排在最前面。这个属性只是视觉上的重排,不影响 DOM 结构和 tab 导航顺序。

常见布局模式

水平垂直居中

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

这是 Flexbox 最经典的用法,一行代码实现水平居中,两行代码实现完全居中。

等宽列

.equal-columns {
display: flex;
}

.equal-columns > * {
flex: 1;
}

所有子元素等宽,无论内容多少。

一侧固定一侧自适应

.sidebar-layout {
display: flex;
}

.sidebar {
flex: 0 0 250px; /* 固定宽度 */
}

.main {
flex: 1; /* 占据剩余空间 */
}

常用于侧边栏布局,侧边栏固定宽度,主内容区自适应。

底部固定

<div class="card">
<div class="content">内容区域</div>
<div class="footer">底部固定</div>
</div>
.card {
display: flex;
flex-direction: column;
min-height: 300px;
}

.content {
flex: 1; /* 填充剩余空间 */
}

.footer {
flex: none; /* 不伸缩 */
}

卡片内容区自动填充,底部按钮始终在底部。

圣杯布局

<div class="holy-grail">
<header>头部</header>
<div class="content">
<main class="main">主内容</main>
<nav class="nav">导航</nav>
<aside class="sidebar">侧边栏</aside>
</div>
<footer>底部</footer>
</div>
.holy-grail {
display: flex;
flex-direction: column;
min-height: 100vh;
}

.content {
display: flex;
flex: 1;
}

.main {
flex: 1;
order: 2;
}

.nav {
flex: 0 0 200px;
order: 1;
}

.sidebar {
flex: 0 0 200px;
order: 3;
}

使用 order 可以让 HTML 中主内容先于侧边栏,提升 SEO 和可访问性。

响应式导航

.nav {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}

.nav-item {
flex: 1;
min-width: 120px;
text-align: center;
}

导航项自动换行,每个项目最小宽度 120px,超出后在新行显示。

小结

这一章我们学习了:

  • Flexbox 的基本概念:容器、项目、主轴、交叉轴
  • 容器属性:flex-direction、flex-wrap、justify-content、align-items、gap
  • 项目属性:flex-grow、flex-shrink、flex-basis、align-self、order
  • 常见布局模式的实现

Flexbox 是一维布局的理想选择,适合处理行或列方向的布局需求。掌握 Flexbox,可以轻松实现过去需要各种技巧才能完成的布局效果。

记住几个关键点:

  • justify-content 控制主轴对齐,align-items 控制交叉轴对齐
  • flex: 1 让项目等分剩余空间
  • flex: 0 0 宽度 创建固定宽度的项目
  • flex-direction: column 切换为垂直布局

下一章我们将学习 CSS Grid 布局,它是二维布局的利器,与 Flexbox 相辅相成。