写在前面
你大概被 float 坑过:清浮动要写 clearfix,垂直居中靠 hack,等分靠百分比加负 margin,改一处塌一片。可 float 的初衷只是 "文字环绕图片",本不该承担布局的职责。
Flex 正是为了一维布局而生:沿一个方向排布元素,自动处理对齐、伸缩、换行与顺序,且不依赖容器尺寸,已被所有主流浏览器完整支持多年。本文从核心概念讲到实战踩坑,配合可运行代码,帮你一次性建立完整的 Flex 知识体系。
一、Flex 的核心概念:容器与项目、主轴与交叉轴
理解 Flex,只需要抓住两组对偶概念:容器(container)与项目(item)、主轴(main axis)与交叉轴(cross axis)。
1.1 容器与项目
对一个元素设置 display: flex,它就成了 flex 容器,它的直接子元素自动成为 flex 项目。
<div class="container"> <!-- flex 容器 -->
<div class="item">1</div> <!-- flex 项目 -->
<div class="item">2\</div> <!-- flex 项目 -->
<div class="item">3\</div> <!-- flex 项目 -->
</div>
.container {
display: flex;
}
这里有两个重要限定词:
-
直接子元素:孙元素不属于 flex 项目,不会被 Flex 规则直接作用。
-
只沿一条轴:Flex 是一维布局模型,它的核心机制都围绕 "主轴" 展开。二维布局(同时处理行列)应该交给 Grid。
1.2 主轴与交叉轴
Flex 布局中,元素沿 主轴 排布,主轴方向由 flex-direction 决定;垂直于主轴的是 交叉轴。
flex-direction: row 主轴 → 交叉轴 ↓(默认)
flex-direction: column 主轴 ↓ 交叉轴 →
关键点:主轴方向是可变的,因此 "水平居中" 在 column 容器里就变成了 "垂直方向上的排布问题"。不要用固定的物理思维(左右、上下)去记 Flex 属性,要用 "主轴 / 交叉轴" 这对逻辑概念去理解,否则遇到 column 方向时很容易懵。
二、开启 Flex:display 的两种形态
/* 容器本身占满一行(块级特性) */
display: flex;
/* 容器表现为行内元素,但子元素仍然是 flex 项目 */
display: inline-flex;
<span class="inline-flex-box"> <!-- 多个 inline-flex 可以并排 -->
<span>a</span>
<span>b</span>
</span>
<span class="inline-flex-box">
<span>c</span>
</span>
display: flex 会让容器变成一个 "块级化的 flex 容器";inline-flex 则让容器在外部表现为行内元素(可以和其他行内内容排在同一行),但内部子元素的布局规则完全一致。
设置 display: flex 后,项目默认会发生什么?
-
子元素默认横向排成一行(
flex-direction: row)。 -
子元素默认不换行(
flex-wrap: nowrap)。 -
子元素的
float、vertical-align等属性失效。 -
子元素的
margin不再折叠(正常块级元素相邻 margin 会折叠,flex 项目不会)。 -
子元素沿主轴排布,在交叉轴方向默认被拉伸填满(
align-items: stretch)。
三、容器属性:布局的 "总开关"
容器上的属性定义了 "项目们如何排布"。共 6 个核心属性:flex-direction、flex-wrap、justify-content、align-items、align-content、gap。
3.1 flex-direction:决定主轴方向
.container {
flex-direction: row; /* 默认,主轴水平,从左到右 */
flex-direction: row-reverse; /* 主轴水平,从右到左 */
flex-direction: column; /* 主轴垂直,从上到下 */
flex-direction: column-reverse; /* 主轴垂直,从下到上 */
}
<div class="container" style="flex-direction: row">
<span>A</span>
<span>B</span>
<span>C</span>
</div>
<!-- 渲染:A B C -->
<div class="container" style="flex-direction: column">
<span>A</span>
<span>B</span>
<span>C</span>
</div>
<!-- 渲染:
A
B
C -->
注意:
row-reverse/column-reverse会 同时反转起始位置 。例如row-reverse下,第一个项目出现在最右侧。但 阅读顺序(DOM 顺序)不变 ,这对无障碍与屏幕阅读器是友好的,应优先用它而不是order来实现视觉反转。
3.2 flex-wrap:是否换行
.container {
flex-wrap: nowrap; /* 默认,不换行,项目会被压缩 */
flex-wrap: wrap; /* 换行,多出来的项目排到下一行 */
flex-wrap: wrap-reverse; /* 换行,且从下往上排 */
}
<style>
.box {
width: 200px;
height: 200px;
display: flex;
flex-wrap: wrap;
}
.box span {
width: 100px;
height: 60px;
}
</style>
<div class="box">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
</div>
<!-- nowrap:4 个元素挤在一行被压缩 -->
<!-- wrap :每行放 2 个,分 2 行显示 -->
3.3 flex-flow:前两者的简写
.container {
flex-flow: <flex-direction><flex-wrap>;
}
/* 等价写法 */
.container {
flex-direction: column;
flex-wrap: wrap;
}
.container {
flex-flow: column wrap;
}
3.4 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; /* 所有间距完全相等(含两端) */
}
<style>
.box {
display: flex;
width: 400px;
}
.box span {
width: 60px;
height: 40px;
margin: 4px;
}
</style>
<!-- space-between:第一个贴左、最后一个贴右、中间等距 -->
<div class="box" style="justify-content: space-between">
<span>1</span>
<span>2</span>
<span>3</span>
</div>
<!-- center:整体居中 -->
<div class="box" style="justify-content: center">
<span>1</span>
<span>2</span>
<span>3</span>
</div>
三者间距计算的区别(容器宽 400,3 个 60px 项目):
| 取值 | 两端间距 | 项目间间距 |
|---|---|---|
space-between | 0 | 各 110px |
space-around | 各 55px | 各 110px(两端各算一份) |
space-evenly | 各 73.3px | 各 73.3px |
justify-content只在 主轴有多余空间时才起作用;当项目溢出容器时,它的表现会退化为 "靠起点溢出"。
3.5 align-items:交叉轴方向的对齐
它决定项目在交叉轴上的对齐方式,与 justify-content 正交。
.container {
align-items: stretch; /* 默认,拉伸填满交叉轴 */
align-items: flex-start;/* 靠交叉轴起点 */
align-items: flex-end; /* 靠交叉轴终点 */
align-items: center; /* 居中 */
align-items: baseline; /* 按首行文字基线对齐 */
}
<style>
.row {
display: flex;
align-items: center;
height: 120px;
}
.row span {
width: 80px;
}
</style>
<!-- 三个高度不同的元素在交叉轴(垂直)方向垂直居中 -->
<div class="row">
<span style="height: 30px">小</span>
<span style="height: 70px">中</span>
<span style="height: 100px">大</span>
</div>
最常用的两个是 center(垂直居中)和 stretch(默认拉伸,让项目填满容器高度)。
经典应用:一行导航里,让图标和文字垂直居中、且不同高度的块都对齐到一条水平线上:
.nav-item {
display: flex;
align-items: center;
}
3.6 align-content:多行(多轴)时的整体对齐
align-content 作用于多行场景,即容器发生换行后,对 "每一整行" 在交叉轴方向上进行分布。注意:单行(未换行)时它无效,此时交叉轴对齐由 align-items 负责。
.container {
flex-wrap: wrap;
align-content: flex-start; /* 各行紧贴交叉轴起点 */
align-content: center; /* 各行整体居中 */
align-content: space-between; /* 各行均匀分布 */
align-content: stretch; /* 默认,各行拉伸填满 */
}
<style>
.grid { display: flex; flex-wrap: wrap; align-content: center; height: 300px; }
.grid span { width: 100px; height: 80px; }
</style>
<!-- 多行项目在容器垂直方向上整体居中,而不是各自拉伸 -->
<div class="grid">
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
<span>6</span>
</div>
3.7 gap:项目间距(告别 margin hack)
gap 是近些年才补全的能力,现在已完全可用,可以替代过去 "用 margin + 负值" 的间距方案。
.container {
gap: 16px; /* 主轴与交叉轴统一 16px */
row-gap: 12px; /* 行间距 */
column-gap: 20px; /* 列间距 */
}
<style>
.cards { display: flex; flex-wrap: wrap; gap: 16px; }
.cards div { width: calc(33.33% - 11px); height: 80px; }
</style>
<div class="cards">
<div>卡片1</div>
<div>卡片2</div>
<div>卡片3</div>
<div>卡片4</div>
<div>卡片5</div>
<div>卡片6</div>
</div>
<!-- 每张卡片间距统一 16px,无需对首尾元素做 margin 修正 -->
gap 相比 "子元素加 margin" 的最大优势:不会在容器边缘产生多余的间距,不需要再对第一个 / 最后一个子元素做负 margin 或 :first-child 修正。
四、项目属性:单个元素的 "自主权"
容器属性决定集体排布,项目属性则允许单个元素打破默认规则。共 6 个:order、flex-grow、flex-shrink、flex-basis、flex、align-self。
4.1 order:控制显示顺序
.item {
order: 0; /* 默认值,按 DOM 顺序排列 */
order: 1; /* 数值越大越靠后 */
order: -1; /* 负数可以排到最前面 */
}
<style>
.box { display: flex; }
.item { width: 60px; height: 40px; margin: 4px; }
.first { order: -1; }
</style>
<div class="box">
<div class="item">默认1</div>
<div class="item">默认2</div>
<div class="item first">提前</div>
</div>
<!-- 渲染顺序:提前 → 默认1 → 默认2(order 相同的按 DOM 顺序) -->
order只改变视觉顺序,不改变 DOM 顺序,也不影响 Tab 键焦点顺序。做视觉重排用它,做语义顺序调整请修改 DOM。
4.2 flex-grow:按比例瓜分剩余空间
flex-grow 决定当主轴有剩余空间时,项目按什么比例放大。
.item {
flex-grow: 0; /* 默认,不放大 */
flex-grow: 1; /* 占据剩余空间 */
}
<style>
.box { display: flex; width: 400px; }
.item { height: 40px; }
.g1 { flex-grow: 1; }
.g2 { flex-grow: 2; }
</style>
<div class="box">
<div class="item g1" style="width:100px">A</div>
<div class="item g2" style="width:100px">B</div>
</div>
<!-- 剩余空间 400 - 200 = 200px,按 1:2 分配 -->
<!-- A 分得约 66.7px,B 分得约 133.3px -->
flex-grow 分配的是 "剩余空间",而不是按权重重新分配总宽度—— 这是新手最常见的误解。项目自身的 width/flex-basis 仍然占据基准份额。
4.3 flex-shrink:空间不足时的收缩比例
当主轴空间不足时,flex-shrink 决定项目如何缩小。
.item {
flex-shrink: 1; /* 默认,空间不足时等比缩小 */
flex-shrink: 0; /* 拒绝缩小,可能溢出 */
}
<style>
.box { display: flex; width: 300px; }
.item { width: 200px; height: 40px; }
.noshrink { flex-shrink: 0; }
</style>
<div class="box">
<div class="item">会缩小</div>
<div class="item noshrink">不缩小</div>
</div>
<!-- 容器 300px,两个项目各 200px,共 400px -->
<!-- "会缩小"被压缩到 100px,"不缩小"保持 200px 并导致溢出 -->
flex-shrink: 0 在 "不允许某元素被压缩"(如图片、长单词)时非常有用。
4.4 flex-basis:项目的主轴基准尺寸
flex-basis 定义项目在主轴上的初始大小,它优先于 width(在 row 方向)。
.item {
flex-basis: auto; /* 默认,回退到 width/height */
flex-basis: 200px;
flex-basis: 30%;
}
优先级:flex-basis(非 auto)> width > 内容宽度。
<style>
.box { display: flex; }
.item { height: 40px; }
</style>
<div class="box">
<!-- flex-basis 生效,width 被忽略 -->
<div class="item" style="flex-basis:150px; width:50px">A</div>
<!-- 没有 flex-basis,width 生效 -->
<div class="item" style="width:100px">B</div>
</div>
4.5 flex 简写:最常用的速记
.item {
flex: none; /* 0 0 auto */
flex: auto; /* 1 1 auto */
flex: 1; /* 1 1 0% —— 最常见的"等分"写法 */
flex: 1 1 200px; /* grow shrink basis */
}
flex: 1 展开为 flex: 1 1 0%,含义是:基准尺寸为 0,所有剩余空间按 grow 比例分配—— 这正是 "等分剩余空间" 的语义。多个 flex: 1 的兄弟项目会平分可用宽度。
<style>
.box { display: flex; width: 600px; }
.item { flex: 1; height: 40px; margin: 0 4px; }
</style>
<div class="box">
<div class="item">等分1</div>
<div class="item">等分2</div>
<div class="item">等分3</div>
</div>
<!-- 三个项目各占约 200px -->
4.6 align-self:单独覆盖容器的 align-items
.item {
align-self: auto; /* 默认,继承容器的 align-items */
align-self: center;
align-self: flex-end;
align-self: stretch;
}
<style>
.box { display: flex; align-items: flex-start; height: 200px; }
.item { width: 80px; }
.special { align-self: flex-end; }
</style>
<!-- 其他项目靠上,special 单独靠下 -->
<div class="box">
<div class="item">上</div>
<div class="item special">下</div>
</div>
4.7 margin: auto:Flex 里的 "万能对齐器"
在 Flex 布局中,margin: auto 会吸收主轴上对应的剩余空间,从而把项目推到指定位置,甚至能做到其他属性做不到的 "双轴居中"。
/* 经典:水平垂直居中,无需指定宽高 */
.container {
display: flex;
}
.item {
margin: auto; /* 主/交叉轴剩余空间全部吸收 → 居中 */
}
<style>
.full {
display: flex;
width: 400px;
height: 300px;
border: 1px solid #ccc;
}
.ball { width: 60px; height: 60px; margin: auto; }
</style>
<div class="full">
<div class="ball"></div>
</div>
<!-- 一个圆形被完美地居中在容器中 -->
更妙的是它可以做 "右对齐 + 自动间距":
.toolbar {
display: flex;
gap: 12px;
}
.toolbar .right {
margin-left: auto; /* 吸收左侧剩余空间 → 被推到最右 */
}
<div class="toolbar">
<button>首页</button>
<button>关于</button>
<button class="right">登录</button>
</div>
<!-- 登录按钮被推到最右侧,无需绝对定位 -->
多个项目同时设
margin-left: auto时,剩余空间会在它们之间平分 —— 可以用来实现 "间距均分到任意位置" 的高级效果。
五、实战:8 个高频布局一次写清
理论讲完,进入 "拿来即用" 的实战环节。以下每个案例都给完整可运行的 HTML/CSS。
5.1 水平垂直居中(最高频)
<!DOCTYPE html>
<html>
<head>
<style>
html, body { height: 100%; margin: 0; }
.center {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.card {
width: 200px;
height: 120px;
background: #f0f4ff;
border-radius: 8px;
text-align: center;
line-height: 120px;
}
</style>
</head>
<body>
<div class="center">
  \<div class="card">我是居中卡片\</div>
  \</div>
\</body>
\</html>
对比传统方案:margin: 0 auto(只水平)、position + transform(需要知道尺寸)、table 单元格(语义差)。Flex 两行搞定且无需固定尺寸。
5.2 两栏 / 经典圣杯布局
<style>
.page { display: flex; min-height: 100vh; }
.sidebar { width: 240px; flex-shrink: 0; background: #f5f5f5; }
.main { flex: 1; background: #fff; padding: 20px; }
</style>
<div class="page">
<aside class="sidebar">侧边栏 240px 固定</aside>
<main class="main">
主内容区,flex: 1 自动填满剩余宽度
</main>
</div>
关键点:侧边栏 flex-shrink: 0 保证不被压缩,主内容 flex: 1 吃满剩余空间。若要 "主内容在前、侧栏在右",用 order 或调整 DOM 顺序即可。
5.3 三栏中间自适应(圣杯布局的现代写法)
<style>
.layout { display: flex; min-height: 100vh; }
.left, .right { width: 200px; flex-shrink: 0; background: #f5f5f5; }
.center { flex: 1; background: #fff; }
</style>
<div class="layout">
<aside class="left">左 200px</aside>
<main class="center">中间自适应</main>
<aside class="right">右 200px</aside>
</div>
在 float 时代,这个布局要配合负 margin、calc 甚至 "圣杯 / 双飞翼" 的奇技淫巧;用 Flex 只需 flex: 1 一句话。
5.4 粘性页脚(Sticky Footer):内容不足时页脚依然贴底
<style>
html, body { height: 100%; margin: 0; }
.app {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header {
background: #333;
color: #fff;
padding: 16px;
}
.content { flex: 1; padding: 16px; } /* 关键:内容区吃满剩余空间 */
.footer { background: #333; color: #fff; padding: 16px; }
</style>
<div class="app">
<header class="header">头部</header>
<main class="content">内容(无论多少,页脚都贴底)</main>
<footer class="footer">页脚</footer>
</div>
原理:容器是 column 方向的 flex,content 设 flex: 1 吸收所有剩余高度,把页脚顶到底部。内容超出时容器随之变高,页脚自然被推下去 —— 完美兼顾 "少内容贴底" 与 "多内容自然流"。
5.5 导航栏(Logo + 菜单 + 操作区)
<style>
.navbar {
display: flex;
align-items: center;
padding: 0 20px;
height: 60px;
background: #fff;
box-shadow: 0 1px 4px rgba(0,0,0,.08);
}
.logo {
font-weight: 700;
font-size: 18px;
}
.menu {
display: flex;
gap: 20px;
margin-left: 40px;
}
.actions {
margin-left: auto;
display: flex;
gap: 12px;
}
</style>
<nav class="navbar">
<div class="logo">MySite</div>
<ul class="menu">
<li>首页</li>
<li>文档</li>
<li>定价</li>
</ul>
<div class="actions">
<button>登录</button>
<button>注册</button>
</div>
</nav>
margin-left: auto 把操作区推到最右,一行代码省掉了 justify-content: space-between 需要额外加占位元素的麻烦。
5.6 响应式卡片网格(自动换行)
<style>
.grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
flex: 1 1 240px; /* 基准 240px,可伸缩 */
min-width: 0; /* 防止内容撑破,见踩坑章节 */
padding: 16px;
border: 1px solid #eee;
border-radius: 8px;
}
</style>
<div class="grid">
<div class="card">卡片 1</div>
<div class="card">卡片 2</div>
<div class="card">卡片 3</div>
<div class="card">卡片 4</div>
</div>
<!-- 视口宽:放得下几列就放几列,多出的自动换行 -->
flex: 1 1 240px 是 "响应式等宽卡片" 的经典写法:每张卡片至少 240px,空间不足就换行,空间充足就均匀铺开。
5.7 固定头部 + 可滚动内容(移动端常见壳子)
<style>
html, body { height: 100%; margin: 0; }
.page {
display: flex;
flex-direction: column;
height: 100vh; /* 关键:锁定视口高度 */
}
.top {
flex-shrink: 0;
height: 50px;
background: #222;
color: #fff;
}
.scroll {
flex: 1;
overflow-y: auto; /* 内容区独立滚动 */
}
.bottom {
flex-shrink: 0;
height: 50px;
background: #222;
color: #fff;
}
</style>
<div class="page">
<div class="top">固定顶栏</div>
<div class="scroll">
<p>长内容,可滚动……</p>
<p>长内容,可滚动……</p>
<p>长内容,可滚动……</p>
<p>长内容,可滚动……</p>
</div>
<div class="bottom">固定底栏</div>
</div>
flex: 1 让中间区域吃掉所有可用高度,overflow-y: auto 让滚动只发生在内容区,顶栏底栏永不滚动。
5.8 图文对齐 / 列表项
<style>
.list-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
border-bottom: 1px solid #f0f0f0;
}
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: #4f8cff;
}
.info { flex: 1; }
.name { font-weight: 600; }
.desc { color: #999; font-size: 12px; }
.time { color: #999; font-size: 12px; }
</style>
<div class="list-item">
<div class="avatar"></div>
<div class="info">
<div class="name">张三</div>
<div class="desc">刚发布了新文章</div>
</div>
<div class="time">5 分钟前</div>
\</div>
头像固定、中间信息 flex: 1 吃满、右侧时间靠边 ——"左侧固定 + 中间弹性 + 右侧固定" 是 Flex 最典型的应用模式,几乎覆盖所有列表页。
六、高频踩坑与最佳实践
理论容易,踩坑难免。以下是 Flex 开发中翻车率最高的几个点,建议熟记。
6.1 坑 1:内容撑破布局(min-width: auto)
现象:flex 项目里放了一段长文本或一张大图,即使容器宽度有限,项目也不压缩,把布局撑破。
原因:flex 项目默认 min-width: auto,即 "最小宽度不小于内容宽度",所以内容(如长单词、图片)拒绝被压缩。
解决:
.item {
min-width: 0; /* row 方向 */
min-height: 0; /* column 方向 */
overflow: hidden; /* 或 auto,配合内容截断 */
}
<style>
.box {
display: flex;
width: 300px;
}
.text {
flex: 1;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<div class="box">
<span class="text">这是一段非常长的文字,如果不加 min-width:0 它会把布局撑破</span>
<span>右侧固定</span>
</div>
<!-- 长文本被截断为省略号,而不是撑破容器 -->
经验法则:只要 flex 项目里可能出现 "不换行的长内容"(长英文单词、URL、图片、canvas),就给它补 min-width: 0。
6.2 坑 2:flex-basis 与 width 的优先级混淆
记住这条铁律:在主轴方向,flex-basis(非 auto)优先于 width。row 方向看 flex-basis,column 方向看 flex-basis 对应高度。
/* row 方向,flex-basis 覆盖 width */
.item {
flex-basis: 200px;
width: 100px;
}
/* 实际 200px */
想清楚 "基准尺寸" 到底是哪个,再决定写 flex-basis 还是 width,不要混用导致预期外结果。
6.3 坑 3:flex: 1 与 min-height 导致的撑开
flex: 1(即 1 1 0%)在 column 方向配合 min-height: auto,子内容多时容器可能被撑高而不是滚动。解决同样是补 min-height: 0,再配合 overflow。
6.4 坑 4:垂直居中被 "内容高度" 欺骗
align-items: center 让项目在交叉轴居中,但如果项目自身有 height: 100% 或内容撑满,居中自然看不出来。排查时先确认 "容器高度已确定"(有 height 或由父级传递),否则 flex 容器高度由内容决定,居中无意义。
/* 容器必须有确定高度,align-items 才有居中的"空间" */
.container {
display: flex;
align-items: center;
height: 300px;
}
6.5 坑 5:flex-wrap 后 justify-content 作用于 "整行" 而非 "全部项目"
换行后,justify-content 是对每一行分别起作用的。如果希望 "最后一行不满时也左对齐"(如卡片布局最后一行只有 2 个),justify-content: space-between 会把它们拉成两端对齐,观感怪异。常见兜底:改用 gap + 普通排布,或给项目固定宽度。
/* 避免:最后一行只有 2 张卡片时被拉成两端对齐 */
.grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
/* 更稳:固定宽度 + gap,最后一行自然左对齐 */
.grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.grid .card {
width: calc(33.33% - 11px);
}
6.6 坑 6:flex 与 float /position 混用
-
设置了
display: flex的容器,其子元素的float完全失效 ——不要再用float+ flex 混排。 -
子元素设
position: absolute会脱离 flex 布局,不再受justify-content/align-items控制(可用绝对定位实现 "覆盖层",但要明确它的脱离语义)。
6.7 最佳实践小结
-
优先用
gap控制间距,不再用 margin hack。 -
能用
flex: 1就不写三连值,语义更清晰。 -
有 "不可压缩内容" 就补
min-width: 0/min-height: 0。 -
视觉反转优先用
row-reverse/column-reverse,少用order(可访问性更好)。 -
align-self只用于 "个别项目特例",全员不同对齐时优先考虑容器属性是否选错了。 -
不确定主轴方向时先画主轴 / 交叉轴示意图,再套属性,别靠记忆猜。
七、Flex vs CSS Grid:到底用哪个?
这是被问得最多的问题。一句话结论:Flex 处理一维(单行 / 单列),Grid 处理二维(行 + 列同时)。
| 维度 | Flexbox | CSS Grid |
|---|---|---|
| 布局模型 | 一维(沿主轴) | 二维(行与列) |
| 典型场景 | 导航、居中对齐、列表、等分 | 整页栅格、复杂区域划分、Dashboard |
| 内容驱动 | 项目沿主轴流动、自动伸缩 | 用轨道(track)显式定义行列 |
| 对齐能力 | 主轴 / 交叉轴两方向对齐 | 更细粒度,可跨单元格控制 |
| 适合 | 组件内部 / 单方向排布 | 页面级 / 区域级整体骨架 |
选择建议:
-
只有一个方向的排布需求(横向导航、垂直列表、居中对齐)→ Flex。
-
同时要管行和列、需要定义网格区域(如 "左侧栏 + 右上 + 右下" 的 Dashboard)→ Grid。
-
混合页面(如 Grid 管整体骨架,骨架内部再用 Flex 排组件)→ 两者搭配,这也是现代 CSS 布局的主流组合。
八、总结
Flex 之所以能 "搞定绝大多数弹性布局",是因为它把过去需要 float、table、inline-block、绝对定位 + 各种 hack 才能实现的对齐、等分、伸缩、换行、排序,收敛成了容器上 6 个属性 + 项目上 6 个属性的清晰模型。
只要记住几条主线,整张知识网就串起来了:
-
定位:
display: flex开启,记住 "容器 vs 项目"。 -
方向:
flex-direction定主轴,flex-wrap定换行。 -
对齐:主轴用
justify-content,交叉轴用align-items(单行)与align-content(多行)。 -
伸缩:
flex-grow/flex-shrink/flex-basis,日常直接用flex: 1。 -
特例:
order改顺序,align-self改个别对齐,margin: auto做 "万能推挤"。 -
间距:一律
gap。 -
兜底:内容撑破就补
min-width: 0。
告别 float,拥抱 Flex,再配合 Grid 做页面级骨架 —— 现代 CSS 布局的绝大部分需求,这套组合就足够覆盖了。遇到问题别急着写样式,先在脑子里画一条主轴、一条交叉轴,答案往往就自己浮现出来了。