0. 简介
伸缩盒(Flexible box)能让普通容器(通常是块级元素)变为伸缩容器,使其有能力改变子元素的尺寸、顺序和对齐方式。
优点:
- 当容器大小发生变化,子元素的大小会被自动调整,原先占据的空间会按比例缩放,以最优的方式填充可用空间。
- 可以轻松解决移动端屏幕尺寸带来的布局问题,还能实现一些棘手的视觉效果,例如多列等高、垂直居中等
注意:伸缩容器的资源不能再使用float和vertical-align属性。
1. 主轴和侧轴
把某个容器元素变为伸缩容器时,这个容器就拥有了主轴和侧轴。主轴和侧轴是伸缩盒的核心概念,容器中资源的排列方式和对齐方式,都是参照这两根轴。
- 主轴:默认从左到右
- 侧轴:默认从上到下
<div class="flex">
<section>1</section>
<section>2</section>
<section>3</section>
</div>

1.1 flex-direction
| flex-direction属性中的关键字 | 描述 |
|---|---|
| row | 将主轴定义为水平方向的轴,它是属性的默认值 |
| row-reverse | 创建的主轴与row相同,但子元素是从右往左排列 |
| column | 将主轴定义为垂直方向的轴 |
| column-reverse | 创建的主轴与column相同,但子元素是从下往上排列 |
flex-direction为row时:




1.2 flex-wrap
伸缩容器中的子元素默认只能排列一行中,如果子元素众多,那么会被自动压缩宽度。如果压到了最小,那么就会从容器中溢出。这点与浮动不同,浮动的元素如果超出了容器的宽度将被自动安排到下一行。
flex-wrap属性用于控制元素的换行,有三个关键字可选。
| 关键字 | 描述 |
|---|---|
| nowrap | 不允许子元素换行,它是属性的默认值 |
| wrap | 允许子元素换行 |
| wrap-reverse | 允许子元素换行,并且容器中的资源会从下到上排列 |
flex-wrap为nowrap时:



2. 对齐方式
- 沿着主轴对齐的属性:justify-content
- 沿着侧轴对齐的属性:align-items、align-self和align-content
2.1 align-items和align-self
- align-items:用来控制容器中的所有子元素的对齐方式
- align-self:只能控制一个子元素的对齐方式,除了align-items的几个关键字外还有一个auto(默认值)
| align-items属性中的关键字 | 描述 |
|---|---|
| flex-start | 子元素仅靠在侧轴起点 |
| flex-end | 子元素仅靠在侧轴终点 |
| center | 子元素被安放在侧轴中部 |
| baseline | 根据子元素中的基线对齐 |
| stretch | 子元素会被拉伸,它是属性的默认值 |
效果图:

<div class="flex" style="align-items:flex-start">
<section>1</section>
<section style="align-self:flex-end">2</section>
<section style="align-self:center">3</section>
<section>4</section>
<section>5</section>
</div>

2.2 align-content
- 用于侧轴对齐,但只在多行的时候才有效果。
- 有6个关键字:flex-start、flex-end、center、stretch、space-between和space-around
- align-content会把多行元素看为一个整体,然后整体对齐
- space-between和space-around会让容器中的各行平均分布,space-around在每行的上下会留间隙,这两块间隙占据的空间相同

2.3 justify-content
- 用于主轴对齐,可选的关键字与align-content相同
- 可选的关键字:flex-start、flex-end、center、space-between和space-around

3. 伸缩性
- 伸缩布局的关键是容器中的子元素可以自动缩放,占据容器的空间,这个功能可以用复合属性flex实现。
- flex由三个属性组成,分别是flex-grow(扩展比率)、flex-shrink(收缩比率)和flex-basis(伸缩基准值)。
- 当容器宽度大于子元素宽度综合的时候,会形成剩余空间;当容器宽度小于子元素宽度总和时,会形成溢出空间。
- 伸缩容器中的子元素按照扩展比率分配剩余空间,按收缩比率减小尺寸避免溢出。
3.1 flex-grow
- 子属性flex-grow的值是数字,
- 如果容器中所有子元素的flex-grow是1,那么每个元素都将占据相同的空间。
- 如果将第二个元素的flex-grow设置为2,那么第二个元素占据的空间是其它子元素的两倍。

3.2 剩余空间
如果容器宽度为300px,并且容器中有三个子元素,这三个子元素的flex-basis属性值分别为:50px、80px、100px,那么剩余空间为70px(=300-50-80-100)。
section:nth-child(1) {
flex: 1 1 50px;
}
section:nth-child(2) {
flex: 2 2 80px;
}
section:nth-child(3) {
flex: 3 3 100px;
}
- flex-grow的总和:1+2+3=6
- 计算元素最终宽度的公式:
- 最终宽度= (flex-grow / flex-grow总和) * 剩余空间 + flex-basis
- 第一个子元素宽度 = 1/6 * 70 + 50 = 61.67
- 第二个子元素宽度 = 2/6 * 70 + 80 = 103.33
- 第三个子元素宽度 = 3/6 * 70 + 100 = 135
3.3 溢出空间
如果容器宽度为300px,并且容器中有三个子元素,这三个子元素的flex-basis属性值分别为:100px、130px、150px,那么溢出空间为80px(=100+130+150 - 300)。
section:nth-child(1) {
flex: 1 1 100px;
}
section:nth-child(2) {
flex: 2 2 130px;
}
section:nth-child(3) {
flex: 3 3 150px;
}
根据三个元素的flex-shrink属性:
- 计算出收缩总和为:1*100+2*130+3*150=810
- 最终宽度 = flex-basis - (flex-shrink * flex-basis) / 收缩总和 * 溢出空间
- 第一个元素宽度 = 100 - (1*100)/810 * 80 = 90.12
- 第二个元素宽度 = 130 - (2*130)/810 * 80 = 104.32
- 第三个元素宽度 = 150 - (2*150)/810 * 80 = 105.56
4. 显示顺序
元素按照HTML文档中的位置排列,位置在前的先显示,位置在后的后显示。order属性能够改变元素的显示顺序,它的值是一个数字,越小越靠前。
<div class="flex">
<section style="order:2">1</section>
<section style="order:1">2</section>
<section style="order:4">3</section>
<section style="order:3">4</section>
</div>
按照order指定的顺序显示