Flexbox 使得很多以前需要复杂 hack(如 float + clear,inline-block + vertical-align)才能实现的布局变得非常简单,尤其是在处理对齐和空间分配方面。
核心概念
理解 Flexbox 的关键在于掌握两个核心概念:Flex 容器 (Flex Container) 和 Flex 项目 (Flex Items) ,以及两条轴线:主轴 (Main Axis) 和 交叉轴 (Cross Axis) 。
-
Flex 容器 (Flex Container):
- 应用了 display: flex; 或 display: inline-flex; 的父元素。
- 它定义了一个 Flexbox 布局环境。
-
Flex 项目 (Flex Items):
- Flex 容器的直接子元素。
- 它们会根据 Flexbox 相关的属性进行布局。
-
轴线 (Axes):
- 主轴 (Main Axis): Flex 项目沿着主轴排列。默认是水平方向(从左到右) 。可以通过 flex-direction 属性改变主轴的方向。
- 交叉轴 (Cross Axis): 垂直于主轴的轴线。默认是垂直方向(从上到下) 。如果主轴变为垂直,交叉轴就变为水平。
关键的 Flexbox 属性
这些属性分为应用于 Flex 容器 的和应用于 Flex 项目 的。
1. Flex 容器属性 (Container Properties):
-
display:
- flex: 将元素定义为块级的 Flex 容器。
- inline-flex: 将元素定义为行内级的 Flex 容器。
-
flex-direction: 定义主轴的方向,从而决定项目排列的方向。
- row (默认值): 主轴为水平方向,起点在左端。
- row-reverse: 主轴为水平方向,起点在右端。
- column: 主轴为垂直方向,起点在上沿。
- column-reverse: 主轴为垂直方向,起点在下沿。
-
flex-wrap: 定义当一条轴线排不下所有项目时,如何换行。
- nowrap (默认值): 不换行,项目可能会溢出容器。
- wrap: 换行,第一行在上方。
- wrap-reverse: 换行,第一行在下方。
-
flex-flow: flex-direction 和 flex-wrap 的简写形式。
- 例如: flex-flow: row wrap;
-
justify-content: 定义项目在 主轴 上的对齐方式。
- flex-start (默认值): 项目向主轴起点对齐。
- flex-end: 项目向主轴终点对齐。
- center: 项目在主轴居中对齐。
- space-between: 两端对齐,项目之间的间隔都相等(首尾项目贴边)。
- space-around: 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
- space-evenly: 所有项目之间的间隔以及项目与边框之间的间隔都完全相等。
-
align-items: 定义项目在 交叉轴 上如何对齐(适用于单行或所有行)。
- stretch (默认值): 如果项目未设置高度(或宽度,取决于交叉轴方向),将占满整个容器的高度(或宽度)。
- flex-start: 项目向交叉轴起点对齐。
- flex-end: 项目向交叉轴终点对齐。
- center: 项目在交叉轴居中对齐。
- baseline: 项目根据其内部文字的基线对齐。
-
align-content: 定义**多根轴线(多行/多列)**在 交叉轴 上的对齐方式。仅在项目换行 (flex-wrap: wrap 或 wrap-reverse) 并且交叉轴上有剩余空间时才生效。如果只有一行,此属性无效。
- stretch (默认值): 轴线占满整个交叉轴。
- flex-start: 轴线向交叉轴起点对齐。
- flex-end: 轴线向交叉轴终点对齐。
- center: 轴线在交叉轴居中对齐。
- space-between: 轴线两端对齐,之间的间隔相等。
- space-around: 每根轴线两侧的间隔相等。
-
gap, row-gap, column-gap: 设置 Flex 项目之间的间距。
- gap: 10px 20px; (row-gap: 10px, column-gap: 20px)
- gap: 15px; (row-gap 和 column-gap 都是 15px)
2. Flex 项目属性 (Item Properties):
-
order: 定义项目的排列顺序。数值越小,排列越靠前,默认为 0。可以为负数。
- 例如: order: -1; 会让该项目排在最前面。
-
flex-grow: 定义项目的放大比例。默认为 0,即如果存在剩余空间,也不放大。
- 如果所有项目的 flex-grow 都为 1,则它们将等分剩余空间。
- 如果一个项目的 flex-grow 为 2,其他项目都为 1,则前者占据的剩余空间将比其他项多一倍。
-
flex-shrink: 定义项目的缩小比例。默认为 1,即如果空间不足,该项目将缩小。
- 如果所有项目的 flex-shrink 都为 1,当空间不足时,都将等比例缩小。
- 如果一个项目的 flex-shrink 为 0,其他项目都为 1,则空间不足时,前者不缩小。
- 负值无效。
-
flex-basis: 定义在分配多余空间之前,项目占据的主轴空间(项目的基准大小)。
- 可以是长度值 (px, em, % 等) 或关键字 auto (默认值,项目的大小是其内容的大小) 或 content。
- 如果设置为 0%,则项目不占据空间,所有空间都将根据 flex-grow 分配。
-
flex: flex-grow, flex-shrink 和 flex-basis 的简写。默认为 0 1 auto。
-
常见值:
- flex: auto; (等同于 1 1 auto):会放大也会缩小,基准大小是内容大小。
- flex: none; (等同于 0 0 auto):既不放大也不缩小,基准大小是内容大小。
- flex: 1; (等同于 1 1 0%):会放大也会缩小,基准大小为 0。这是让项目等分剩余空间的常用方法。
- flex: 2; (等同于 2 1 0%)
-
-
align-self: 允许单个项目有与其他项目不一样的对齐方式,可覆盖 align-items 属性。默认为 auto,表示继承父元素的 align-items 属性。
- 可选值与 align-items 相同 (stretch, flex-start, flex-end, center, baseline)。
Flexbox 的优势:
- 强大的对齐能力: 水平、垂直居中变得异常简单。
- 空间分配灵活: 可以轻松控制项目如何填充可用空间或在空间不足时如何收缩。
- 顺序无关性: 可以通过 order 属性轻松改变项目的视觉顺序,而不必更改 HTML 结构。
- 自动处理等高列: 在 row 方向下,默认的 align-items: stretch 可以轻松实现等高列效果。
- 响应式友好: 非常适合构建响应式布局的组件。
常用场景:
- 导航栏(水平或垂直)
- 项目列表(卡片式布局,需要换行)
- 组件内部元素的对齐(按钮和输入框的对齐)
- 需要平均分配空间的布局
- 垂直居中任何元素
Flexbox vs. Grid:
- Flexbox 主要设计用于一维布局(要么是行,要么是列)。虽然可以换行,但控制力主要在一维方向上。
- Grid Layout 则设计用于二维布局(同时处理行和列)。
通常,页面级的整体布局可能更适合 Grid,而组件内部或特定区域的一维排列则非常适合 Flexbox。两者可以很好地结合使用。
Flexbox 是现代 CSS 布局的基石之一,强烈建议深入学习和实践!
案例 1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flexbox Examples</title>
<link rel="stylesheet" href="1.css"> 我们将在 style.css 中编写 CSS
</head>
<body>
<h1>Flexbox 布局示例</h1>
<!-- 示例 1: 基本水平排列 -->
<h2>示例 1: 基本水平排列 (默认)</h2>
<div class="container example1">
<div class="item item-1">1</div>
<div class="item item-2">2</div>
<div class="item item-3">3</div>
</div>
<!-- 示例 2: 水平垂直居中 -->
<h2>示例 2: 水平垂直居中</h2>
<div class="container example2">
<div class="item item-1">1</div>
<div class="item item-2">2</div>
<div class="item item-3">3</div>
</div>
<!-- 示例 3: 改变主轴方向为垂直 -->
<h2>示例 3: 改变主轴方向为垂直</h2>
<div class="container example3">
<div class="item item-1">1</div>
<div class="item item-2">2</div>
<div class="item item-3">3</div>
</div>
<!-- 示例 4: 项目换行 -->
<h2>示例 4: 项目换行</h2>
<div class="container example4">
<div class="item item-1">1</div>
<div class="item item-2">2</div>
<div class="item item-3">3</div>
<div class="item item-4">4</div>
<div class="item item-5">5</div>
<div class="item item-6">6</div>
</div>
<!-- 示例 5: 空间分配 (space-between) -->
<h2>示例 5: 空间分配 (space-between)</h2>
<div class="container example5">
<div class="item item-1">1</div>
<div class="item item-2">2</div>
<div class="item item-3">3</div>
</div>
<!-- 示例 6: 项目弹性增长 (flex-grow) -->
<h2>示例 6: 项目弹性增长 (flex-grow)</h2>
<div class="container example6">
<div class="item item-1 grow-1">1 (flex: 1)</div>
<div class="item item-2 grow-2">2 (flex: 2)</div>
<div class="item item-3 grow-1">3 (flex: 1)</div>
</div>
<!-- 示例 7: 改变项目顺序 (order) -->
<h2>示例 7: 改变项目顺序 (order)</h2>
<div class="container example7">
<div class="item item-1 order-3">1 (order: 3)</div>
<div class="item item-2 order-1">2 (order: 1)</div>
<div class="item item-3 order-2">3 (order: 2)</div>
</div>
<!-- 示例 8: 单个项目对齐 (align-self) -->
<h2>示例 8: 单个项目对齐 (align-self)</h2>
<div class="container example8">
<div class="item item-1">1</div>
<div class="item item-2 self-end">2 (align-self: flex-end)</div>
<div class="item item-3">3</div>
</div>
<!-- 示例 9: 使用间距 (gap) -->
<h2>示例 9: 使用间距 (gap)</h2>
<div class="container example9">
<div class="item item-1">1</div>
<div class="item item-2">2</div>
<div class="item item-3">3</div>
<div class="item item-4">4</div>
<div class="item item-5">5</div>
</div>
</body>
</html>
body {
font-family: sans-serif;
}
.container {
border: 3px solid steelblue;
background-color: lightgray;
padding: 10px;
margin-bottom: 30px; /* 区分示例 */
min-height: 150px; /* 给容器一些最小高度,便于观察垂直对齐 */
display: flex; /* !! 核心:启用 Flexbox !! */
}
.item {
border: 1px solid #666;
background-color: lightcoral;
padding: 20px;
margin: 5px; /* 给项目一些外边距,便于区分 */
text-align: center;
font-size: 1.2em;
color: white;
min-width: 50px; /* 确保项目有基本宽度 */
}
/* 为不同项目添加不同颜色(可选,便于区分) */
.item-1 { background-color: #e74c3c; }
.item-2 { background-color: #f1c40f; }
.item-3 { background-color: #2ecc71; }
.item-4 { background-color: #3498db; }
.item-5 { background-color: #9b59b6; }
.item-6 { background-color: #1abc9c; }
/* --- 各示例特定样式 --- */
/* 示例 1: 基本水平排列 (默认) */
/* 无需额外样式,默认就是 flex-direction: row; flex-wrap: nowrap; align-items: stretch; */
/* 示例 2: 水平垂直居中 */
.example2 {
justify-content: center; /* 主轴(水平)居中 */
align-items: center; /* 交叉轴(垂直)居中 */
}
/* 示例 3: 改变主轴方向为垂直 */
.example3 {
flex-direction: column; /* 主轴变为垂直 */
align-items: flex-start; /* 交叉轴(现在是水平)起点对齐,防止项目拉伸 */
/* 注意:此时 justify-content 控制垂直对齐,align-items 控制水平对齐 */
height: 300px; /* 给个固定高度看效果 */
}
.example3 .item {
width: 80%; /* 限制宽度,否则默认会水平撑满 */
}
/* 示例 4: 项目换行 */
.example4 {
flex-wrap: wrap; /* 允许项目换行 */
/* 可以调整容器宽度来看换行效果 */
/* width: 350px; */
}
/* 示例 5: 空间分配 (space-between) */
.example5 {
justify-content: space-between; /* 两端对齐,项目间等间距 */
/* 试试 space-around 或 space-evenly 看看区别 */
/* justify-content: space-around; */
/* justify-content: space-evenly; */
}
/* 示例 6: 项目弹性增长 (flex-grow) */
/* 我们将 flex 属性直接写在 HTML 元素的 style 里,或者像这样定义类 */
.example6 .item {
flex-shrink: 0; /* 为演示方便,禁止缩小 */
}
.example6 .grow-1 {
flex-grow: 1; /* 占据 1 份剩余空间 */
/* 或者简写 flex: 1; (等同于 flex: 1 1 0%) */
}
.example6 .grow-2 {
flex-grow: 2; /* 占据 2 份剩余空间 */
/* 或者简写 flex: 2; (等同于 flex: 2 1 0%) */
}
/* 示例 7: 改变项目顺序 (order) */
.example7 .order-1 {
order: 1;
}
.example7 .order-2 {
order: 2;
}
.example7 .order-3 {
order: 3;
}
/* 注意:上面例子中,HTML 结构是 1-2-3,但 order 让它们显示为 2-3-1 */
/* 也可以使用负数,比如 order: -1 让元素排最前 */
/* 示例 8: 单个项目对齐 (align-self) */
.example8 {
align-items: flex-start; /* 先让所有项目默认靠上对齐 */
height: 200px; /* 确保有足够垂直空间看效果 */
}
.example8 .self-end {
align-self: flex-end; /* 单独让这个项目在交叉轴(垂直)底部对齐 */
/* 试试 align-self: center; 或 stretch; */
}
/* 示例 9: 使用间距 (gap) */
.example9 {
flex-wrap: wrap; /* 允许换行 */
gap: 15px; /* 同时设置行间距和列间距为 15px */
/* 或者分别设置: */
/* row-gap: 20px; */
/* column-gap: 10px; */
}
.example9 .item {
margin: 0; /* 注意:使用 gap 时,通常不再需要给 item 设置 margin */
}
案例 2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.container {
display: flex;
}
.box {
flex: 1;
background: lightblue;
text-align: center;
padding: 20px;
margin: 5px;
}
</style>
</head>
<body>
<div class="container">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
</div>
</body>
</html>
案例 3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.container {
display: flex;
}
.left,
.right {
width: 100px;
background: #ddd;
}
.center {
flex: 1;
background: #eee;
}
</style>
</head>
<body>
<div class="container">
<div class="left">左</div>
<div class="center">中</div>
<div class="right">右</div>
</div>
</body>
</html>
案例 4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.card-list {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.card {
flex: 1 1 200px;
background: lightgreen;
padding: 20px;
}
</style>
</head>
<body>
<div class="card-list">
<div class="card">卡片1</div>
<div class="card">卡片2</div>
<div class="card">卡片3</div>
<div class="card">卡片4</div>
</div>
</body>
</html>