说明:本文flex-direction默认是row,且不再介绍flex基础知识。若想学习基础语法,可参阅阮一峰老师的博文Flex 布局教程:语法篇
一:flex-basis 和 width之争,flex-basis完胜
结论:当一个元素同时被设置了 flex-basis (除值为 auto 外) 和 width (或者在 flex-direction: column 情况下设置了height) , flex-basis 具有更高的优先级。
即:一个元素同时设置了flex-basis(除值为 auto 外) 和 width,width失效。
栗子1:flex-basis不为auto
<!--html-->
<div class="flex_box">
<div class="flex-item_left">Item One</div>
<div class="flex-item_middle">Item Two</div>
</div>
<style>
/*css*/
.flex_box {
display: flex;
flex-direction: row;
background-color: #fff;
width: 320px;
height: 40px;
margin: 0 auto;
}
.flex-item_left {
width: 100px;
flex-basis: 80px;
background-color: #fb3;
}
.flex-item_middle {
flex-basis: 80px;
width: 100px;
background-color: #96AD91;
}
</style>
浏览器效果:
Item One和Item Two同时定义了width: 100px;和 flex-basis: 80px,只是顺序有差异。
结果:在css中,无论with和flex-basis谁先定义,最后生效的总是 flex-basis。
栗子2:flex-basis为auto
<!--html-->
<div class="flex_box">
<div class="flex-item_left">Item One</div>
<div class="flex-item_middle">Item Two</div>
</div>
<style>
/*css*/
.flex_box {
display: flex;
flex-direction: row;
background-color: #fff;
width: 320px;
height: 40px;
margin: 0 auto;
}
.flex-item_left {
width: 100px;
flex-basis: auto;
background-color: #fb3;
}
.flex-item_middle {
flex-basis: auto;
width: 100px;
background-color: #96AD91;
}
</style>
本例中,仅将栗子1中flex-basis的值改为auto
浏览器效果:
这里说明了,flex-basis优先级高的条件是,值不能为auto。
二:flex简写
flex属性是 flex-grow,flex-shrink 和 flex-basis的简写,默认值为0 1 auto。
有些属性可选,被省略后会被自动补全。
分类 | 简写 | 实际的值 | 说明 |
---|---|---|---|
<flex-grow> | flex: 1; | flex: 1 1 0%; | <flex-grow> 1/0 是<flex-grow> 值,此时简写会扩展为: |
flex: 0; | flex: 0 1 0%; | ||
<flex-basis> | flex: 100px; | flex: 1 1 100px; | <flex-basis> 100px / auto 是<flex-basis> 值,此时简写会扩展为: |
flex: auto; | flex: 1 1 auto; | ||
flex: initial; | flex: 0 1 auto; | 能屈不能伸 | |
flex: none; | flex: 0 0 auto; | 注意区分none和0。 它俩本质并不相同。 | |
双值语法 | flex: 1 1; | flex: 1 1 0%; | 双值语法 第一个值只能是<flex-grow>, 第二个值可能是<flex-shrink>或<flex-basis> <flex-shrink>会扩展为: flex: <flex-grow> <flex-shrink> 0%。 <flex-basis>会扩展为: flex: <flex-grow> 1 <flex-basis> |
flex: 1 100px; | flex: 1 1 100px; |
关于简写的值,上述表格并未全部列出。但应对平时的开发足矣。
三:flex-grow原理
这个属性规定了 flex-grow 项在 flex 容器中分配剩余空间的相对比例。
- 它的数据类型为number,取值范围为[0, +∞)
- 默认为0,即如果存在剩余空间,也不放大。
- 实际分配空间=剩余分配空间*MIN(1, Sum(flex-grow))
- 它是对剩余空间的相对占比,而不是当前元素在flex容器中的占比。
- 所有子元素的flex-basis都为0,flex-grow就是子元素在flex容器中的占比
- flex-basis: auto元素 参与分配(不考虑width的影响)
栗子3 - Sum(flex-grow)≥1
每个子元素都是 flex: <flex-grow>;
<div class="flex-grow_box">
<div class="flex-grow-item_a">A</div>
<div class="flex-grow-item_b">B</div>
<div class="flex-grow-item_c">C</div>
<div class="flex-grow-item_d">D</div>
<div class="flex-grow-item_e">E</div>
</div>
<style>
.flex-grow_box {
display: flex;
flex-direction: row;
background-color: #fff;
width: 400px;
height: 40px;
margin: 0 auto;
}
.flex-grow-item_a {
flex: 1;
background-color: #1F4642;
}
.flex-grow-item_b {
flex: 1;
background-color: #96AD91;
}
.flex-grow-item_c {
flex: 1;
background-color: #58a;
}
.flex-grow-item_d {
flex: 2;
background-color: #fb3;
}
.flex-grow-item_e {
flex: 3;
background-color: #564D38;
}
</style>
浏览器效果:
- 每个子元素貌似是按照1:1:1:2:3的比例分配的,是因为每个子元素的flex-basis是0%。
- box总宽是400px,每个子元素占宽0(flex-basis是0%),剩余分配空间是400px。
- 每个子元素按照flex-grow(1:1:1:2:3)分配400px。
特例:如果box只有两个子元素,且每个子元素flex: 1; 那这俩子元素宽度1:1等分。
栗子3也说明一点,如果flex所有子元素的flex-basis都是0,flex-grow就是当前元素在flex容器中的占比。
栗子4 - Sum(flex-grow)<1
每个子元素都是 flex: <flex-grow>;
<div class="flex-grow_box">
<div class="flex-grow-item_a">A</div>
<div class="flex-grow-item_b">B</div>
<div class="flex-grow-item_c">C</div>
<div class="flex-grow-item_d">D</div>
<div class="flex-grow-item_e">E</div>
</div>
<style>
.flex-grow_box {
display: flex;
flex-direction: row;
background-color: #fff;
width: 400px;
height: 40px;
margin: 0 auto;
}
.flex-grow-item_a {
flex: 0.1;
background-color: #1F4642;
}
.flex-grow-item_b {
flex: 0.1;
background-color: #96AD91;
}
.flex-grow-item_c {
flex: 0.1;
background-color: #58a;
}
.flex-grow-item_d {
flex: 0.2;
background-color: #fb3;
}
.flex-grow-item_e {
flex: 0.3;
background-color: #564D38;
}
</style>
浏览器效果:
栗子4,是栗子3中将所有的flex-grow的值除以10的效果。
- box总宽是400px,每个子元素占宽0(flex-basis是0%),剩余分配空间是400px。
- 每个子元素按照flex-grow(1:1:1:2:3)分配320px。
实际分配空间 = 剩余分配空间 * Sum(flex-grow)。- 栗子3中,Sum(flex-grow) = 8,可实际分配空间对应的系数是1。
实际分配空间 = 剩余分配空间 * 1。- 可以理解成地主家也没有余粮(最多1),几个S儿子要财产,多了没有(≤1),少了就给自己留点(Sum(flex-grow))。
- 总结一下这个公式:
实际分配空间=剩余分配空间*MIN(1, Sum(flex-grow))。
这时如果有个Q1,剩余空间都会被占用吗?答:不会。这里需要考虑Sum(flex-grow) 是不是大于1。
栗子5 - 正常分配剩余空间
<div class="flex-grow_box">
<div class="flex-grow-item_a">A</div>
<div class="flex-grow-item_b">B</div>
<div class="flex-grow-item_c">C</div>
<div class="flex-grow-item_d">D</div>
<div class="flex-grow-item_e">E</div>
</div>
.flex-grow_box {
display: flex;
flex-direction: row;
background-color: #fff;
width: 400px;
height: 40px;
margin: 0 auto;
}
.flex-grow-item_a {
flex: 1 0 40px;
background-color: #1F4642;
}
.flex-grow-item_b {
flex: 1 0 80px;
background-color: #96AD91;
}
.flex-grow-item_c {
flex: 2 0 40px;
background-color: #58a;
}
.flex-grow-item_d {
flex: 2 0 80px;
background-color: #fb3;
}
.flex-grow-item_e {
flex: 4 0 40px;
background-color: #564D38;
}
浏览器效果:
- 子元素的flex-basis--①,合计占宽(sum=280px)
小于box宽,存在剩余空间(本例中=400-sum=120px)- 子元素的flex-grow合计是10,
实际分配空间=剩余分配空间*MIN(1, Sum(flex-grow)) = 120 * 1 = 120px。- 子元素按照flex-grow(1:1:2:2:4)分配120px,得到分配空间-- ②
- 实际宽度③ = ① + ②
栗子5也说明了flex-grow是对剩余空间的相对占比,而不是当前元素在flex容器中的占比。
栗子6 - flex-basis: auto元素 参与分配
<div class="flex-grow_box">
<div class="flex-grow-item_a">A</div>
<div class="flex-grow-item_b">B</div>
<div class="flex-grow-item_c">C</div>
</div>
.flex-grow_box {
display: flex;
flex-direction: row;
background-color: #fff;
width: 400px;
height: 40px;
margin: 0 auto;
}
.flex-grow-item_a {
flex: 1 0 100px;
background-color: #1F4642;
}
.flex-grow-item_b {
flex: 2 0 auto;
background-color: #96AD91;
}
.flex-grow-item_c {
flex: 3 0 100px;
background-color: #58a;
}
浏览器效果:
- 子元素的flex-basis/auto--①,合计占宽(sum=200px + 10.04(子元素B))
小于box宽,存在剩余空间(本例中=400-sum=189.96px)- 子元素的flex-grow合计是6,
实际分配空间=剩余分配空间*MIN(1, Sum(flex-grow)) = 189.96 * 1 = 189.96px。- 子元素按照flex-grow(1:2:3)分配 189.96 px,得到分配空间-- ②
- 实际宽度③ = ① + ②
重点说明,flex-basis为auto时,这里未将width考虑在内。实际宽度公式并未考虑width的情况,如果有小可爱提出本文公式有问题,这里不做解释。
四:flex-shrink原理
这个属性指定了 flex 元素的收缩规则
- 它的数据类型为number,取值范围为[0, +∞),默认为1
- flex 元素仅在默认宽度之和大于容器的时候才会发生收缩
- 实际收缩空间=需要收缩空间*MIN(1, Sum(flex-shrink))
- 实际收缩比例,受 (flex-shrink*flex-basis) 的影响--这点和flex-grow重点区分
- flex-basis: auto的子元素,不设置width,不参与收缩--这点和flex-grow重点区分
flex-basis: auto的子元素,设置width,正常收缩
栗子7 - Sum(flex-shrink)≥1
<div class="flex-shrink_box">
<div class="flex-shrink-item_a">A</div>
<div class="flex-shrink-item_b">B</div>
<div class="flex-shrink-item_c">C</div>
</div>
.flex-shrink_box {
display: flex;
flex-direction: row;
background-color: #fff;
width: 400px;
height: 40px;
margin: 0 auto;
}
.flex-shrink-item_a {
flex: 1 1 100px;
background-color: #1F4642;
}
.flex-shrink-item_b {
flex: 1 2 200px;
background-color: #96AD91;
}
.flex-shrink-item_c {
flex: 1 3 300px;
background-color: #58a;
}
浏览器效果:
- 子元素的flex-basis--①,合计占宽(sum=600px)
大于box宽,空间不足需收缩(本例中=400-sum=-200px)- 子元素的flex-shrink合计是6,
实际收缩空间=需要收缩空间*MIN(1, Sum(flex-shrink)) = 200 * 1 = 200px。- 子元素按照(flex-shrink*flex-basis) 进行收缩:
按照1*100 : 2*200 : 3*300=1:4:9 收缩200px,得到收缩空间--②
A:200 * 1 / 14 = 14.29 // 保留两位小数
B:200 * 4 / 14 = 57.14 // 和浏览器有0.01px的精度差
C:200 * 9 / 14 = 128.57- 实际宽度③ = ① - ②
栗子8 - Sum(flex-shrink)<1
<div class="flex-shrink_box">
<div class="flex-shrink-item_a">A</div>
<div class="flex-shrink-item_b">B</div>
<div class="flex-shrink-item_c">C</div>
</div>
.flex-shrink_box {
display: flex;
flex-direction: row;
background-color: #fff;
width: 400px;
height: 40px;
margin: 0 auto;
}
.flex-shrink-item_a {
flex: 1 0.1 100px;
background-color: #1F4642;
}
.flex-shrink-item_b {
flex: 1 0.2 200px;
background-color: #96AD91;
}
.flex-shrink-item_c {
flex: 1 0.3 300px;
background-color: #58a;
}
浏览器效果:
- 子元素的flex-basis--①,合计占宽(sum=600px)
大于box宽,空间不足需收缩(本例中=400-sum=-200px)- 子元素的flex-shrink合计是0.6,
实际收缩空间=需要收缩空间*MIN(1, Sum(flex-shrink)) = 200 * 0.6 = 120px。- 子元素按照(flex-shrink*flex-basis) 进行收缩:
按照0.1*100 : 0.2*200 : 0.3*300= 1:4:9 收缩200px,得到收缩空间--②
A:120 * 1 / 14 = 8.57 // 保留两位小数
B:120 * 4 / 14 = 34.29 // 和浏览器有0.01px的精度差
C:120 * 9 / 14 = 77.14- 实际宽度③ = ① - ②
栗子9 - flex-basis: auto元素,不参与收缩(不设置width)
<div class="flex-shrink_box">
<div class="flex-shrink-item_a">A</div>
<div class="flex-shrink-item_b">B</div>
<div class="flex-shrink-item_c">C</div>
</div>
.flex-shrink_box {
display: flex;
flex-direction: row;
background-color: #fff;
width: 400px;
height: 40px;
margin: 0 auto;
}
.flex-shrink-item_a {
flex: 1 0.4 200px;
background-color: #1F4642;
}
.flex-shrink-item_b {
flex: 1 0.2 auto;
background-color: #96AD91;
}
.flex-shrink-item_c {
flex: 1 0.5 300px;
background-color: #58a;
}
浏览器效果:
- 子元素的flex-basis/auto--①,合计占宽(sum=500px + 10.04(子元素B))
大于box宽,空间不足需收缩(本例中=400-sum=-110.04px)- 子元素的flex-shrink合计是0.9(不含auto),
实际收缩空间=需要收缩空间*MIN(1, Sum(flex-shrink)) = 110.04 * 0.9 = 99.036px。- 子元素按照(flex-shrink*flex-basis) 进行收缩:
按照0.4*200 : 0.5*300 = 8 : 15 收缩 99.036px,得到收缩空间--②
A:99.036 * 8 / 23 = 34.45 // 保留两位小数 -- 和浏览器有0.01px的精度差
B:auto 不参与收缩
C:99.036 * 15 / 23 = 64.59- 实际宽度③ = ① - ②
无实例说明:flex-basis: auto元素,设置了width。将width代入flex-basis,正常收缩。
五:flex-basis、min-width、max-width之争
默认情况下,元素不会缩短至小于内容框尺寸,若想改变这一状况,请设置元素的min-width 与 min-height属性。
栗子10
<div class="flex_box">
<div class="flex-item_a1">A1</div>
<div class="flex-item_a2">A2</div>
<div class="flex-item_b1">B1</div>
<div class="flex-item_b2">B2</div>
<div class="flex-item_c1">C1</div>
<div class="flex-item_c2">C2</div>
<div class="flex-item_c3">C3</div>
<div class="flex-item_d1">D1</div>
<div class="flex-item_d2">D2</div>
<div class="flex-item_e1">E1</div>
<div class="flex-item_e2">E2</div>
<div class="flex-item_e3">E3</div>
</div>
<style>
.flex_box {
display: flex;
flex-direction: row;
background-color: #fff;
height: 40px;
margin: 0 auto;
color: #fff;
}
.flex-item_a1 {
min-width: 30px;
flex: 0 0 40px;
background-color: #1F4642;
}
.flex-item_a2 {
min-width: 50px;
flex: 0 0 40px;
background-color: #96AD91;
}
.flex-item_b1 {
flex: 0 0 40px;
max-width: 30px;
background-color: #1F4642;
}
.flex-item_b2 {
flex: 0 0 40px;
max-width: 50px;
background-color: #96AD91;
}
.flex-item_c1 {
min-width: 30px;
max-width: 50px;
flex: 0 0 20px;
background-color: #1F4642;
}
.flex-item_c2 {
min-width: 30px;
max-width: 50px;
flex: 0 0 40px;
background-color: #96AD91;
}
.flex-item_c3 {
min-width: 30px;
max-width: 50px;
flex: 0 0 60px;
background-color: #58a;
}
.flex-item_d1 {
min-width: 40px;
max-width: 40px;
flex: 0 0 30px;
background-color: #1F4642;
}
.flex-item_d2 {
min-width: 40px;
max-width: 40px;
flex: 0 0 50px;
background-color: #96AD91;
}
.flex-item_e1 {
min-width: 40px;
max-width: 30px;
flex: 0 0 20px;
background-color: #1F4642;
}
.flex-item_e2 {
min-width: 40px;
max-width: 30px;
flex: 0 0 35px;
background-color: #96AD91;
}
.flex-item_e3 {
min-width: 40px;
max-width: 30px;
flex: 0 0 50px;
background-color: #58a;
}
</style>
浏览器效果:
设置不同的值,来总结规律:
- 只有min-width和flex-basis,实际宽度 = MAX(min-width, flex-basis)
- 只有max-width和flex-basis,实际宽度 = MIN(max-width, flex-basis)
- 同时有min-width、max-width、flex-basis
- min-width < max-width,实际宽度取值范围 [min-width, max-width]
flex-basis < max-width:实际宽度 = MAX(min-width, flex-basis)
flex-basis ≥ max-width:实际宽度 = MIM(max-width, flex-basis)- min-width ≥ max-width,实际宽度 = min-width
所以在写CSS代码时,使用flex-basis时,谨慎使用max-width和min-width。
六:flex: 1; 两栏布局
使用场景,两栏布局:左边宽度固定,右边宽度自适应
<div class="box">
<div class="left"></div>
<div class="right"></div>
</div>
/*css*/
.box {
display: flex;
height: 100px;
}
.left {
/*下面三行代码,任选一行*/
width: 100px;
/*flex: 0 0 100px;*/
/*flex: 0 1 100px;*/
background-color: #1F4642;
}
.right {
flex: 1;
background-color: #96AD91;
}
- .left:
1)只设定了width,flex就是initial; (即:flex: 0 1 auto)。能屈不能伸。
2)如果不设置width,设置flex:0 0 100px; 或 0 1 100px; 都阔以。
所谓宽度固定,就是通过width或者flex-basis定宽,且flex-grow为0。 - .right:设置了flex: 1(即:flex: 1 1 0%)。能屈能伸。
- .box宽大于100px时,超出100px的部分都是.right的,也就是所谓的自适应布局。
原理并不复杂,实现也很简单。
七:flex: auto;
谈flex: auto; , 本质是讨论元素flex-basis值为auto的情况。
元素设置了flex-basis: auto后,元素会根据自身宽高来确定尺寸,就是靠内容撑起自身。
The End.