Flexbox(弹性盒子布局)是现代 CSS 布局的核心。它让一维布局变得简单直观,无论是水平排列、垂直居中还是等分空间,Flexbox 都能轻松实现。
基本概念#
容器与项目#
Flexbox 布局涉及两类元素:
- Flex 容器:设置了
display: flex的元素 - Flex 项目:容器的直接子元素
<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 的关键:
- 主轴(Main Axis):项目排列的方向
- 交叉轴(Cross Axis):垂直于主轴的方向
默认情况下,主轴是水平的(从左到右),交叉轴是垂直的(从上到下)。
容器属性#
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-direction 和 flex-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 简写#
flex 是 flex-grow、flex-shrink、flex-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: 1 1 0:初始大小为 0,完全按比例分配空间flex: auto=flex: 1 1 auto:初始大小根据内容决定,再按比例分配剩余空间
/* 如果项目内容不同,flex: 1 会让它们宽度相等 *//* flex: auto 会让内容多的项目更宽 */🤔 为什么 gap 不生效?
确认使用了 display: flex 或 display: grid。gap 不适用于普通块级元素。
🤔 项目超出容器怎么办?
.container { flex-wrap: wrap; /* 允许换行 */}
/* 或限制项目最小宽度 */.item { min-width: 0; /* 允许项目缩小到比内容更小 */}🤔 如何让最后一行左对齐?
这是 Flexbox 的一个痛点,可以用伪元素填充:
.grid::after { content: ''; flex: auto;}或者使用 CSS Grid 更合适。
Flexbox 是现代布局的基础,掌握它能解决大部分一维布局问题。对于复杂的二维布局,下一篇我们将学习 CSS Grid,它是 Flexbox 的完美补充。