Skip to content

Flexbox 布局

Flexbox(弹性盒子布局)是现代 CSS 布局的核心。它让一维布局变得简单直观,无论是水平排列、垂直居中还是等分空间,Flexbox 都能轻松实现。

基本概念#

容器与项目#

Flexbox 布局涉及两类元素:

<div class="container">
<!-- Flex 容器 -->
<div class="item">项目 1</div>
<div class="item">项目 2</div>
<div class="item">项目 3</div>
</div>
.container {
display: flex; /* 或 inline-flex */
}

主轴与交叉轴#

🎯 理解两条轴是掌握 Flexbox 的关键:

默认情况下,主轴是水平的(从左到右),交叉轴是垂直的(从上到下)。

容器属性#

flex-direction#

定义主轴方向:

.container {
flex-direction: row; /* 默认:水平从左到右 */
flex-direction: row-reverse; /* 水平从右到左 */
flex-direction: column; /* 垂直从上到下 */
flex-direction: column-reverse; /* 垂直从下到上 */
}

flex-wrap#

控制项目是否换行:

.container {
flex-wrap: nowrap; /* 默认:不换行,可能溢出 */
flex-wrap: wrap; /* 换行 */
flex-wrap: wrap-reverse; /* 反向换行 */
}

flex-flow#

flex-directionflex-wrap 的简写:

.container {
flex-flow: row wrap;
}

justify-content#

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

.container {
justify-content: flex-start; /* 默认:起点对齐 */
justify-content: flex-end; /* 终点对齐 */
justify-content: center; /* 居中 */
justify-content: space-between; /* 两端对齐,项目间等距 */
justify-content: space-around; /* 项目两侧等距 */
justify-content: space-evenly; /* 所有间距相等 */
}

视觉对比(主轴水平时):

flex-start: |■ ■ ■ |
flex-end: | ■ ■ ■|
center: | ■ ■ ■ |
space-between: |■ ■ ■|
space-around: | ■ ■ ■ |
space-evenly: | ■ ■ ■ |

align-items#

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

.container {
align-items: stretch; /* 默认:拉伸填满 */
align-items: flex-start; /* 交叉轴起点 */
align-items: flex-end; /* 交叉轴终点 */
align-items: center; /* 交叉轴居中 */
align-items: baseline; /* 基线对齐 */
}

align-content#

当有多行时,控制行在交叉轴上的分布:

.container {
flex-wrap: wrap; /* 需要换行才有效 */
align-content: flex-start;
align-content: flex-end;
align-content: center;
align-content: space-between;
align-content: space-around;
align-content: stretch; /* 默认 */
}

gap#

设置项目之间的间距:

.container {
gap: 20px; /* 行列间距相同 */
gap: 20px 10px; /* 行间距 列间距 */
row-gap: 20px; /* 单独设置行间距 */
column-gap: 10px; /* 单独设置列间距 */
}

🎯 使用 gap 比给项目设置 margin 更优雅,无需处理首尾项目的边距。

项目属性#

flex-grow#

定义项目的放大比例:

.item {
flex-grow: 0; /* 默认:不放大 */
}
.item-expand {
flex-grow: 1; /* 占据剩余空间 */
}
<div class="container">
<div class="item" style="flex-grow: 1;">1</div>
<div class="item" style="flex-grow: 2;">2</div>
<div class="item" style="flex-grow: 1;">1</div>
</div>
<!-- 项目宽度比例为 1:2:1 -->

flex-shrink#

定义项目的缩小比例:

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

当容器空间不足时,flex-shrink 值越大的项目缩小得越多。

flex-basis#

定义项目在分配空间前的初始大小:

.item {
flex-basis: auto; /* 默认:根据内容或 width 决定 */
flex-basis: 200px; /* 固定初始宽度 */
flex-basis: 30%; /* 百分比 */
flex-basis: 0; /* 完全由 flex-grow 决定 */
}

flex 简写#

flexflex-growflex-shrinkflex-basis 的简写:

.item {
flex: 0 1 auto; /* 默认值 */
flex: 1; /* 等同于 flex: 1 1 0 */
flex: auto; /* 等同于 flex: 1 1 auto */
flex: none; /* 等同于 flex: 0 0 auto */
}

🎯 推荐使用简写形式:

/* 等分空间 */
.equal-item {
flex: 1;
}
/* 固定宽度,不缩放 */
.fixed-item {
flex: 0 0 200px;
}
/* 根据内容确定宽度,可缩放 */
.content-item {
flex: auto;
}

align-self#

覆盖单个项目的交叉轴对齐方式:

.container {
align-items: flex-start;
}
.special-item {
align-self: flex-end; /* 只有这个项目靠下 */
}

order#

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

.item:first-child {
order: 2; /* 移到后面 */
}
.item:last-child {
order: -1; /* 移到最前 */
}

默认 order 为 0,值越小越靠前。

常见布局模式#

水平垂直居中#

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

这是 Flexbox 最经典的用法,一行代码解决了困扰前端多年的居中问题。

导航栏#

.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
}
.navbar-brand {
font-weight: bold;
font-size: 1.25rem;
}
.navbar-nav {
display: flex;
gap: 1.5rem;
list-style: none;
margin: 0;
padding: 0;
}
.navbar-actions {
display: flex;
gap: 0.5rem;
}
<nav class="navbar">
<a class="navbar-brand" href="/">Logo</a>
<ul class="navbar-nav">
<li><a href="/">首页</a></li>
<li><a href="/about">关于</a></li>
<li><a href="/blog">博客</a></li>
</ul>
<div class="navbar-actions">
<button>登录</button>
<button>注册</button>
</div>
</nav>

卡片列表#

.card-list {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.card {
flex: 1 1 300px; /* 最小 300px,可以增长 */
max-width: 400px;
padding: 1.5rem;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

等高列#

.columns {
display: flex;
gap: 1rem;
}
.column {
flex: 1;
padding: 1rem;
background: #f3f4f6;
border-radius: 8px;
}
/* 默认 align-items: stretch 让所有列等高 */

固定 + 自适应布局#

.layout {
display: flex;
min-height: 100vh;
}
.sidebar {
flex: 0 0 250px; /* 固定 250px */
background: #1f2937;
}
.main {
flex: 1; /* 占据剩余空间 */
padding: 2rem;
}

底部固定#

.page {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header {
/* 自然高度 */
}
.main {
flex: 1; /* 占据中间所有空间 */
}
.footer {
/* 自然高度,始终在底部 */
}

媒体对象#

.media {
display: flex;
gap: 1rem;
align-items: flex-start;
}
.media-image {
flex: 0 0 auto; /* 不缩放 */
width: 64px;
height: 64px;
border-radius: 50%;
}
.media-body {
flex: 1; /* 占据剩余空间 */
}

表单行#

.form-row {
display: flex;
gap: 0.5rem;
align-items: center;
}
.form-row label {
flex: 0 0 100px; /* 固定标签宽度 */
}
.form-row input {
flex: 1; /* 输入框填满剩余空间 */
}
.form-row button {
flex: 0 0 auto; /* 按钮不缩放 */
}

实战案例#

完整页面布局#

.app {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background: white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.body {
display: flex;
flex: 1;
}
.sidebar {
flex: 0 0 240px;
padding: 1rem;
background: #f9fafb;
border-right: 1px solid #e5e7eb;
}
.content {
flex: 1;
padding: 2rem;
overflow: auto;
}
.footer {
padding: 1rem 2rem;
background: #1f2937;
color: white;
text-align: center;
}

响应式卡片网格#

.grid {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card {
flex: 1 1 calc(33.333% - 1rem);
min-width: 280px;
padding: 1.5rem;
background: white;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
}
@media (max-width: 768px) {
.card {
flex: 1 1 100%;
}
}

按钮组#

.btn-group {
display: inline-flex;
border-radius: 6px;
overflow: hidden;
}
.btn-group button {
flex: 1;
padding: 0.5rem 1rem;
border: 1px solid #d1d5db;
background: white;
cursor: pointer;
}
.btn-group button:not(:first-child) {
border-left: none;
}
.btn-group button:hover {
background: #f3f4f6;
}
.btn-group button.active {
background: #3b82f6;
color: white;
border-color: #3b82f6;
}

常见问题#

🤔 flex: 1 和 flex: auto 有什么区别?

/* 如果项目内容不同,flex: 1 会让它们宽度相等 */
/* flex: auto 会让内容多的项目更宽 */

🤔 为什么 gap 不生效?

确认使用了 display: flexdisplay: gridgap 不适用于普通块级元素。

🤔 项目超出容器怎么办?

.container {
flex-wrap: wrap; /* 允许换行 */
}
/* 或限制项目最小宽度 */
.item {
min-width: 0; /* 允许项目缩小到比内容更小 */
}

🤔 如何让最后一行左对齐?

这是 Flexbox 的一个痛点,可以用伪元素填充:

.grid::after {
content: '';
flex: auto;
}

或者使用 CSS Grid 更合适。


Flexbox 是现代布局的基础,掌握它能解决大部分一维布局问题。对于复杂的二维布局,下一篇我们将学习 CSS Grid,它是 Flexbox 的完美补充。