参考
介绍
传统的布局方案,基于盒模型,依赖display属性、position属性和float属性。其对于某些特殊的布局(如垂直居中),实现起来比较麻烦。
在 2009 年,W3C 提出了一种新的布局方案——Flex 布局(Flexible Box 布局,弹性盒子布局),其相比于传统的布局方案,更为灵活和简便。目前,Flex 布局已经得到了所有浏览器的支持。
将元素的display属性设置为flex或inline-flex后,即可开启 Flex 布局:
// 块级元素
.block-box {
display: flex;
}
// 行内元素
.inline-box {
display: inline-flex;
}
同时,该元素会自动成为 Flex 容器,简称容器。且容器的所有子元素会自动成为 Flex 容器成员,简称项目。项目的float、clear、vertical-align属性将失效。
容器中默认存在两根轴:主轴和侧轴。主轴和侧轴互相垂直,类似于平面坐标系中的 x 轴和 y 轴。项目将自动沿着主轴方向排列,排满时将沿侧轴方向堆砌,即在侧轴方向上换行(前提是容器flex-wrap属性不为nowrap)。
调试
可使用Flex 布局在线调试工具来快速配置 Flex 布局和查看 Flex 布局效果:
对于该工具的介绍请见此文。
容器的属性
flex-direction
flex-direction属性决定主轴的方向,进而决定项目的排列方向,其值可能为:
.container {
// 主轴方向从左向右→(默认值)
flex-direction: row;
// 主轴方向从右向左←
flex-direction: row-reverse;
// 主轴方向从上向下↓
flex-direction: column;
// 主轴方向从下向上↑
flex-direction: column-reverse;
}
flex-wrap
flex-wrap属性决定侧轴的方向,进而决定项目的换行方向,其值可能为:
.container {
// 侧轴无方向(默认值)
// 相当于不换行
flex-wrap: nowrap;
// 主轴方向水平时,侧轴方向从上向下↓
// 主轴方向竖直时,侧轴方向从左向右→
// 相当于顺序换行
flex-wrap: wrap;
// 主轴方向水平时,侧轴方向从下向上↑
// 主轴方向竖直时,侧轴方向从右向左←
// 相当于逆序换行
flex-wrap: wrap-reverse;
}
flex-flow
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,其值可能为:
.container {
// 主轴方向从左向右,侧轴无方向(默认值)
// 即项目排列方向→,不换行
flex-flow: row nowrap;
// 主轴方向从左向右,侧轴方向从上向下
// 即项目排列方向→,换行方向↓,与现代书写方向相同
flex-flow: row wrap;
// 主轴方向从左向右,侧轴方向从下向上
// 即项目排列方向→,换行方向↑
flex-flow: row wrap-reverse;
// 主轴方向从右向左,侧轴无方向
// 即项目排列方向←,不换行
flex-flow: row-reverse nowrap;
// 主轴方向从右向左,侧轴方向从上向下
// 即项目排列方向←,换行方向↓
flex-flow: row-reverse wrap;
// 主轴方向从右向左,侧轴方向从下向上
// 即项目排列方向←,换行方向↑
flex-flow: row-reverse wrap-reverse;
// 主轴方向从上向下,侧轴无方向
// 即项目排列方向↓,不换行
flex-flow: column nowrap;
// 主轴方向从上向下,侧轴方向从左向右
// 即项目排列方向↓,换行方向→
flex-flow: column wrap;
// 主轴方向从上向下,侧轴方向从右向左
// 即项目排列方向↓,换行方向←,与中国古代书写方向相同
flex-flow: column wrap-reverse;
// 主轴方向从下向上,侧轴无方向
// 即项目排列方向↑,不换行
flex-flow: column-reverse nowrap;
// 主轴方向从下向上,侧轴方向从左向右
// 即项目排列方向↑,换行方向→
flex-flow: column-reverse wrap;
// 主轴方向从下向上,侧轴方向从右向左
// 即项目排列方向↑,换行方向←
flex-flow: column-reverse wrap-reverse;
}
可基于以下配置对flex-flow的值进行修改,查看其不同值的对应效果,以验证上述规律:
.container {
width: 200px;
height: 200px;
flex-flow: <flex-direction> | <flex-wrap>;
.item-1,
.item-2,
.item-3 {
width: 100px;
height: 100px;
}
}
justify-content
justify-content属性决定了项目沿主轴方向的对齐方式,其值可能为:
.container {
// 主轴方向上,起点对齐(默认值)
justify-content: flex-start;
// 主轴方向上,终点对齐
justify-content: flex-end;
// 主轴方向上,居中对齐
justify-content: center;
// 主轴方向上,项目之间空隙相等
justify-content: space-between;
// 主轴方向上,项目两侧空隙相等
justify-content: space-around;
}
align-content
align-content属性决定了项目沿侧轴方向的对齐方式(如果项目只有一行,则该属性无效),其值可能为:
.container {
// 如果项目height未设置或为auto
// 项目拉伸至占满侧轴(默认值)
align-content: stretch;
// 侧轴方向上,起点对齐
align-content: flex-start;
// 侧轴方向上,终点对齐
align-content: flex-end;
// 侧轴方向上,居中对齐
align-content: center;
// 侧轴方向上,项目之间空隙相等
align-content: space-between;
// 侧轴方向上,项目两侧空隙相等
align-content: space-around;
}
place-content
place-content属性是align-content属性和justify-content属性的简写形式,其可能值见此文。
.container {
place-content: <align-content> | <justify-content>;
}
align-items
align-items属性决定了同一行项目沿侧轴方向的对齐方式,即项目在主轴方向上的垂直对齐方式,其值可能为:
.container {
// 如果项目height未设置或为auto
// 则拉伸至占满该行(默认值)
align-items: stretch;
// 侧轴方向上,起点对齐
align-items: flex-start;
// 侧轴方向上,终点对齐
align-items: flex-end;
// 侧轴方向上,居中对齐
align-items: center;
// 侧轴方向上,基线对齐
align-items: baseline;
}
项目的属性
order
order属性决定了项目沿主轴方向的排列顺序,其值可能为:
.item {
// 数值越小,项目排列越靠前(默认值为1)
order: <integer>;
}
align-self
align-self属性会覆盖容器的align-items属性,其值可能为:
.item {
// 继承容器的align-items属性(默认值)
align-self: auto;
align-self: stretch;
align-self: flex-start;
align-self: flex-end;
align-self: center;
align-self: baseline;
}
flex-basis
flex-basis属性会覆盖项目的width属性(当主轴方向水平时)或height属性(当主轴方向垂直时),下文中的flex-grow和flex-shrink都基于flex-basis进行计算,其值可能为:
.item {
// 设置为与width或height相同的值(默认值)
flex-basis: auto;
flex-basis: <length>;
}
然而,flex-basis属性仍然受max-width/max-height和min-width/min-height属性的约束。
flex-grow
flex-grow属性决定了项目沿主轴方向的伸长系数,只在容器有剩余空间时有效,其值可能为:
.item {
// (默认值为0)
flex-grow: <number>;
}
关于flex-grow属性的计算过程为:
flex-grow属性小于等于0的项目不受影响,不会伸长。- 对剩余项目的
flex-grow属性进行求和,将结果记为sum。 - 分以下情况进行讨论。
sum ≥ 1 时
.container {
display: flex;
width: 800px;
.item1 {
flex-basis: 50px;
}
.item2 {
flex-basis: 100px;
flex-grow: 1;
}
.item3 {
flex-basis: 150px;
flex-grow: 3;
}
.item4 {
flex-basis: 200px;
flex-grow: 6;
}
}
计算过程:
- 计算剩余宽度:
剩余宽度 = 容器宽度 - 项目总宽度,所以:剩余宽度 = 800px - 500px = 300px。
- 计算各项目权重占比:
权重 = <flex-grow>,所以:总权重 = sum = 1 + 3 + 6 = 10。项目2权重 = 1,项目2权重占比 = 1 / 10 = 0.1。项目3权重 = 3,项目3权重占比 = 3 / 10 = 0.3。项目4权重 = 6,项目4权重占比 = 6 / 10 = 0.6。
- 计算各项目伸长宽度:
伸长宽度 = 权重占比 * 剩余宽度,所以:项目2伸长宽度 = 0.1 * 300px = 30px。项目3伸长宽度 = 0.3 * 300px = 90px。项目4伸长宽度 = 0.6 * 300px = 180px。
- 计算各项目伸长后宽度:
伸长后宽度 = <flex-basis> + 伸长宽度,所以:项目2伸长后宽度 = 100px + 30px = 130px。项目3伸长后宽度 = 150px + 90px = 240px。项目4伸长后宽度 = 200px + 180px = 380px。
sum < 1 时
计算过程基本与sum > 1时的情况相同,但在第 3 步中,各项目的伸长宽度为sum * 权重占比 * 剩余宽度。
flex-shrink
flex-shrink属性决定了项目沿主轴方向的缩短系数,只在容器空间发生溢出时有效,其值可能为:
.item {
// (默认值为1)
flex-shrink: <number>;
}
关于flex-shrink属性的计算过程为:
flex-shrink属性小于等于0的项目不受影响,不会缩短。- 对剩余项目的
flex-shrink属性进行求和,将结果记为sum。 - 分以下情况进行讨论。
sum ≥ 1 时
.container {
display: flex;
width: 800px;
.item1 {
flex-basis: 100px;
}
.item2 {
flex-basis: 200px;
flex-shrink: 6;
}
.item3 {
flex-basis: 300px;
flex-shrink: 3;
}
.item4 {
flex-basis: 400px;
flex-shrink: 1;
}
}
计算过程:
- 计算溢出宽度:
溢出宽度 = 项目总宽度 - 容器宽度,所以:溢出宽度 = 800px - 1000px = 200px。
- 计算各项目权重占比:
权重 = <flex-shrink> * <flex-basis>,所以:总权重 = 1200 + 900 + 400 = 2500。项目2权重 = 1200,项目2权重占比 = 1200 / 2500 = 0.48。项目3权重 = 900,项目3权重占比 = 900 / 2500 = 0.36。项目4权重 = 400,项目4权重占比 = 400 / 2500 = 0.16。
- 计算各项目缩短宽度:
缩短宽度 = 权重占比 * 溢出宽度,所以:项目2伸长宽度 = 0.48 * 200px = 96px。项目3伸长宽度 = 0.36 * 200px = 72px。项目4伸长宽度 = 0.16 * 200px = 32px。
- 计算各项目缩短后宽度:
缩短后宽度 = 原始宽度 - 缩短宽度,所以:项目2缩短后宽度 = 200px - 96px = 104px。项目3缩短后宽度 = 300px - 72px = 228px。项目4缩短后宽度 = 400px - 32px = 368px。
sum < 1 时
计算过程基本与sum > 1时的情况相同,但在第 3 步中,各项目的缩短宽度为sum * 权重占比 * 溢出宽度。
flex
flex属性是flex-grow属性、flex-shrink和flex-basis属性的简写形式,其值可能为:
.item {
// 相当于flex:0 0 auto;
flex: none;
// 相当于flex:1 1 auto;
flex: auto;
flex: <flex-grow> <flex-shrink> <flex-basis>;
}