资料来源 css-tricks.com
1. 原先布局的痛点
对于那些特殊布局非常不方便
- 比如在父内容里面垂直居中一个块内容
- 比如使容器的所有子项等分可用宽度/高度,而不管有多少宽度/高度可用
- 比如使多列布局中的所有列采用相同的高度,即使它们包含的内容量不同
所以长久以来,非常期待一种真正可以用于对元素布局的方案
- 2009年,W3C 提出了Flex 布局,可以简便、完整、响应式地实现各种页面布局
2. 认识flexbox
Flexbox翻译为弹性盒子
- 弹性盒子是一种用于按行或按列布局元素的一维布局方法
元素可以膨胀以填充额外的空间, 收缩以适应更小的空间- 通常使用Flexbox来进行布局的方案称之为flex布局(flex layout)
- 任何一个容器都可以指定为 Flex 布局
flex布局是目前web开发中使用最多的布局方案
- flex 布局(Flexible 布局,弹性布局)
- 目前特别在移动端可以说已经完全普及
- 在PC端也几乎已经完全普及和使用,只有非常少数的网站依然在用浮动来布局
为什么需要flex布局
- 长久以来,CSS 布局中唯一可靠且跨浏览器兼容的布局工具只有 floats 和 positioning
- 但是这两种方法本身存在很大的局限性,并且用于布局实在是无奈之举
3. flex布局兼容性
- 可以在 caniuse 上查询到具体的兼容性

4. flex布局的重要概念
两个重要的概念
开启了 flex 布局的元素叫 flex container
flex container 里面的直接子元素叫做 flex item

当flex container中的子元素变成了flex item时,具备一下特点
- flex item的布局将受flex container属性的设置来进行控制和布局
flex item不再严格区分块级元素和行内级元素flex item 的float,clear,vertical-algin属性将失效- flex item默认情况下是包裹内容的,但是可以设置宽度和高度
设置 display 属性为 flex 或者 inline-flex 可以成为 flex container
flex:flex container 以block-level形式存在inline-flex:flex container 以inline-level形式存在
5. flex布局的模型

- 容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)
- 主轴的开始位置叫做
main start,结束位置叫做main end - 交叉轴的开始位置叫做
cross start,结束位置叫做cross end - 项目默认沿主轴排列
- 单个项目占据的主轴空间叫做
main size,占据的交叉轴空间叫做cross size
6. flex container属性
6.1. flex-direction
看flex-direction设置谁为主轴,剩下的就是侧轴
flex items 默认都是沿着 main axis(主轴)从 main start 开始往 main end 方向排布
flex-direction 决定了主轴的方向,有 4 个取值
属性值 说明 row 从左到右,默认 row-reverse 从右到左 column 从上到下 column-reverse 从下到上 
6.2. flex-wrap
- 默认情况下,项目都排在一条线上,flex布局中默认不换行
- flex-wrap 决定了 flex container是单行还是多行
| 属性值 | 说明 |
|---|---|
| nowrap | 不换行(默认) |
| wrap | 换行 |
| wrap-reverse | 多行(对比 wrap,cross start 与 cross end 相反) 第一行在下方 |

6.3. flex-flow
flex-flow 属性是 flex-direction 和 flex-wrap 的简写
flex-flow: <flex-direction> || <flex-wrap>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
- 顺序任何, 并且都可以省略
## justify-content
- justify-content 决定了 flex items 在 main axis上的对齐方式
| 属性值 | 说明 | 图形化 |
| ------------- | ------------------------------------------------------------ | :------------------------: |
| flex-start | 默认值,与main start对齐 |  |
| flex-end | 与main end对齐 |  |
| center | 在main axis居中对齐 |  |
| space-between | 首个flex item放置于起点<br>末尾flex item放置于终点<br>其余flex items等分剩余空间 |  |
| space-around | 每个flex items两边都有间距<br>每个flex items两边分配相同的空间<br/>flex item 与 cross start、cross end 的间距是flex items之间间距的一半 |  |
| space-evenly | 每个flex items两端都有间距<br>所有的空间等分<br/>flex item 与 cross start、cross end 的间距等于flex items之间的距离 |  |
## align-items 单行
- align-items 决定了flex items在 cross axis 上的对齐方式
- flex items为单行时使用
| 属性值 | 说明 | 图形化 |
| ---------- | ------------------------------------------------------------ | :----------------------: |
| normal | 默认值,在弹性布局中,效果和stretch一样 | |
| stretch | 当flex items在 cross axis 方向的 size 为 auto 时,即高度为auto或不设置高度时,自动拉伸至填充容器 |  |
| flex-start | 与 cross start 对齐 |  |
| flex-end | 与 cross end 对齐 |  |
| center | 在 cross axis 居中对齐 |  |
| baseline | 与基准线对齐<br/>可以跟字号有关,跟vertical-align属性有关 |  |
## align-content 多行
- align-content 决定了多行flex items在 cross axis 上的对齐方式,用法与 justify-content 类似
- 并且只能用于子项出现换行的情况,单行下无效
| 属性值 | 说明 | 图形化 |
| ------------- | ------------------------------------------------------------ | -------------------------- |
| stretch | 默认值,flex items不设置高度的情况下,轴线高度占满整个cross axis |  |
| flex-start | 与 cross start 对齐 |  |
| flex-end | 与 cross end 对齐 |  |
| center | 在 cross axis 居中对齐 |  |
| space-between | 每根轴线之间的间隔都相等<br/>与 cross start、cross end两端对齐 |  |
| space-around | 每根轴线两侧的间隔都相等<br/>轴线 与 cross start、cross end 的间距是轴线之间间距的一半 |  |
| space-evently | 存在兼容性问题 | |
# flex-item属性
## order
- order 决定了 flex items 的排布顺序
- 可以设置任意`整数`(正整数、负整数、0),`值越小就越排在前面`
- 默认值是 0

## align-self
- align-self 允许单个项目有与其他项目不一样的对齐方式,可覆盖 flex container 设置的 align-items
- auto(默认值):遵从 flex container 的 align-items 设置
- stretch、flex-start、flex-end、center、baseline,效果跟 align-items 一致

## flex-grow 扩展
- flex-grow 决定了 flex items 如何扩展(拉伸/成长)
- 可以设置任意`非负数字(正小数、正整数、0),默认值是 0`
- 当 flex container 在 main axis 方向上`有剩余 size` 时,flex-grow 属性才会有效
- 如果所有 flex items 的 flex-grow 总和 sum 超过 1,每个 flex item 扩展的 size 为
- flex container 的剩余 size x ( flex-grow / sum)
- flex items 扩展后的最终 size 不能超过 max-width 或 max-height

## flex-shrink 收缩
- flex-shrink 决定了 flex items 如何收缩(缩小)
- 可以设置任意`非负数字(正小数、正整数、0)`
- 默认值为1,多个元素在同一行时默认会显示压缩
- 当 flex items 在 main axis 方向上`超过了 flex container 的 size`,flex-shrink 属性才会有效
- 如果所有 flex items 的 flex-shrink 总和超过 1,每个 flex item 收缩的 size为
- flex items 超出 flex container 的 size x ( 收缩比例 / 所有 flex items 的收缩比例之和)
- flex items 收缩后的最终 size 不能小于 min-width 或 min-height
## flex-basis
- flex-basis 用来设置 flex items 在 main axis 方向上的基础尺寸
- auto(默认值)
- 具体的宽度数值(100px)
### 案例
当遇到长单词,原无法显示的剩余内容时,元素会自动进行拉伸

- 设置 div.item2元素 width:120px; 时,aaaaa_bbbbb_ccccc_ddddd无法在一行中完整显示,会被剪裁
- 改为 flex-basis:120px; 或者 auto时,自动拉伸
- HTML
```html
<div class="content">
<div class="item item1">1</div>
<div class="item item2">aaaaa_bbbbb_ccccc_ddddd</div>
<div class="item item3">3</div>
</div>
CSS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21.content {
display: flex;
width: 400px;
height: 200px;
background-color: orange;
}
.item {
width: 120px;
height: 120px;
}
.item1 {
background-color: bisque;
}
.item2 {
width: auto;
flex-basis: 120px;
background-color: pink;
}
.item3 {
background-color: yellow;
}同时设置 width:120px; 和 flex-basis:120px; 时,flex-basis其实是生效的,但是设置的width又将尺寸限制在120px
6.3.1. 决定基础尺寸的因素
- 决定 flex items 最终基础尺寸的因素,从优先级高到低
- max-width/max-height/min-width/min-height
- flex-basis
- width/height
- 内容本身的 size
6.4. flex属性
- flex 是 flex-grow || flex-shrink || flex-basis 的简写,flex 属性可以指定1个,2个或3个值
1 | flex = none |[ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ] |
单值语法:值必须为以下其中之一
- 一个无单位数(number):它会被当作 flex-grow 的值
- 一个有效的宽度(width)值: 它会被当作 flex-basis 的值
- 关键字none,auto
- flex: flex-grow flex-shrink flex-basis
- none 相当于 flex: 0 0 auto
- auto 相当于 flex: 1 1 auto
双值语法:第一个值必须为一个无单位数,并且它会被当作 flex-grow 的值
- 第二个值必须为以下之一
- 一个无单位数:它会被当作 flex-shrink 的值
- 一个有效的宽度值:它会被当作 flex-basis 的值
- 第二个值必须为以下之一
三值语法
- 第一个值必须为一个无单位数,并且它会被当作 flex-grow 的值
- 第二个值必须为一个无单位数,并且它会被当作 flex-shrink 的值
- 第三个值必须为一个有效的宽度值, 并且它会被当作 flex-basis 的值
7. 多列行个数不同布局问题
7.1. 问题
- 设置主轴上元素贴边对齐
- 希望1,4,5号元素贴边的情况下,6,7号元素布局跟2,3号元素一样
- 情况出现在最后一行元素

1 | .content>.item.item$*10{$} |
7.2. 解决
7.2.1. 计算间距
- 方法一:舍弃space-between,通过计算元素之间的距离来达到效果
- 父盒子宽度(500) - 子盒子宽度(110)*4 = 剩余空间(60)
- 剩余空间(60)/(4个元素3个间隙)3 = 20px,元素之间距离为20px,即margin-right
- 但要去掉每列最后一个元素的margin-right
- 缺点:方法需要计算,不利于维护
1 | .content { |
7.2.2. 添加新元素
方法二:容器内放置新元素
span/div/p/i/…都可以
新元素的宽度等于子元素的宽度- 新元素没有设置高度而不会显示
新元素的个数等于列数-2- 当元素个数为5,第2行有3个元素: div.item5, 新元素, 新元素,div.item5因为space-between放置在贴main start位置
- 当元素个数为6,第2行有4个元素: div.item5, div.item6, 新元素, 新元素,占满
- 当元素个数为7,第2行还是有4个元素:div.item5, div.item6, div.item7, 新元素,占满
- 当元素个数为8,第2行还是有4个元素:div.item5, div.item6, div.item7, div.item8,占满
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21.content>.item.item$*7{$}+span*2
.content {
width: 500px;
background-color: orange;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.item {
width: 110px;
height: 140px;
background-color: pink;
margin-bottom: 5px;
}
.content > span {
width: 110px;
}