文章目录
1. 前言
flex 弹性布局是常见的一种自适应布局方式, 父容器的属性控制整体布局,子项属性控制子项布局。这里主要了解和总结子项中常用的 flex 属性。
2. flex语法
2.1 与 flex 相关的三个属性
弹性布局的 flex
属性定义了如何分配 flex容器的剩余空间。
剩余空间: flex 容器大小减去所有 flex 项的大小总和。
flex 是 <flex-grow>
<flex-shrink>
<flex-basis>
三者的简写,默认值为 0 1 auto。
flex-grow 表弹性扩展,指定容器剩余空间多余时的分配规则,默认为0,多余空间不分配。
flex-shrink 表弹性收缩,指定容器剩余空间不足时的分配规则,默认值为 1,空间不足要分配;如果为 0,表示不分配。
flex-basis 表基础尺寸,指定 flex 元素在分配空间前的大小,默认值为 auto,即项目本身大小。
如果剩余空间为正数, 即容器有多余空间, 则按照子项的 flex-grow 定义的比例进行扩展;
若为负数, 则剩余空间不足, 按照 flex-shrink 定义的比例进行收缩。
2.1.1 各种值及含义
flex: none | auto | [< 'flex-grow' > < 'flex-shrink' >? || < 'flex-basis' > ];
根据以上 MDN 官方给出的语法,存在以下几种情况:
1.单值语法
如关键字(none 或 auto)、纯数值表示 < ‘flex-grow’ > 或 带单位表示 < ‘flex-basis’ >;
单值语法 | 等同于 | 备注 |
---|---|---|
flex: initial | flex: 0 1 auto | 初始值 |
flex: none | flex: 0 0 auto | - - |
flex: auto | flex: 1 1 auto | - - |
flex: 1 | flex: 1 1 0% | 只要 flex-grow设置值了, flex-basis 的值必为 0%,而不是默认值auto。 |
flex: 0 | flex: 0 1 0% | 当希望元素充分利用剩余空间,但是各自的尺寸按照各自内容进行分配时适用 |
flex: 100px | flex: 1 1 100px | 只要 flex-basis 设置值了, flex-grow 的值必为1 ,而不是默认值0。 |
2.双值语法
第一个值表 < ‘flex-grow’ > ;
若第二个值为纯数值,则为 < ‘flex-shrink’ > ;
若第二个值带单位表示长度,则表示 < ‘flex-basis’ > ;
双值语法 | 等同于 | 备注 |
---|---|---|
flex: 1 2 | flex: 1 2 0% | 只要 flex-grow设置值了, flex-basis 的值必为 0%,而不是默认值auto。 |
flex: 1 100px | flex: 1 1 100px | 只要 flex-basis 设置值了, flex-grow 的值必为1 ,而不是默认值0。 |
3.三值语法
对应 < ‘flex-grow’ > < ‘flex-shrink’ > < ‘flex-basis’ > 的值;
2.2 默认值 flex: initial
2.2.1 含义
它等同于 flex:0 1 auto。
0 表示 flex-grow: 0 , 当子项总长度<容器宽度时,不会撑满,按照实际宽高存在;
1 表示 flex-shrink:1,当子项总长度>容器宽度时,子项会收缩相对应的比例;
auto 表示 flex-basis:auto,尺寸自适应于内容,即子项宽度由内容决定。
2.2.2 适用场景
适用于子项总长度小于总容器的场景,例如按钮、标题、小图标等小部件的排版布局。
2.2.3 区分于 flex: auto
flex: initial === flex:0 1 auto
flex: auto === flex:1 1 auto
区别在于前者 flex-grow 值为0,后者为1。
当有多余空间时,flex: auto 子项的宽度会撑满容器,其他情况两者相同。
2.3 flex:1 的含义及应用
2.3.1 含义
flex:1 等同于 flex: 1 1 0%。
子项的宽度不由内容决定,根据剩下的空间进行相应比例的伸缩。
2.3.2 适用场景
场景一:各子项宽度等分
思路:子项都设置 flex:1
场景二:希望元素充分利用剩余空间,如:多列布局中,希望某一列或某几列撑满剩下空间
思路:固定列宽度固定,自适应列设置 flex:1
2.3.3 应用中出现的问题
溢出不省略
代码:
<div class="flex-container">
<div class="flex-item-left"></div>
<div class="flex-item-right">
<div class="text">这是一段长长长长长长长长的文字</div>
</div>
</div>
.flex-container{
display: flex;
align-item: center;
padding: 10px;
background-color: #e9eff9;
width: 200px;
height: 50px;
}
.flex-item-left{
width: 50px;
min-width: 50px;
height: 100%;
background-color: #638cd0;
margin-right: 10px;
}
.flex-item-right{
flex: 1;
}
.text{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
分析:
在分配剩余空间之前,决定当前子元素的实际空间大小的优先级为: flex-basis
> width
> 内容宽度。
同时, 这个实际空间大小会受到元素的 min-width
和 max-width
的限制 。
浏览器默认为flex容器的子元素设置了 min-width: auto; min-height: auto
,这意味着子元素的最小宽度和高度不能小于其内容的宽度和高度。
当 flex 子项内容足够多时, 最小宽度为内容宽度, 内容溢出。
参考:
flex布局中 text-overflow:ellipsis 失效
flex弹性布局 子元素内容超出盒子容器宽度问题
解决思路:
直接把 min-width: auto;
这个默认属性覆盖,设置为 min-width: 0
,即使其内容为空或者宽度很小,也可以使得flex子元素在flex容器中正确地布局
元素不对齐
代码及示例链接如下
<div class="numbers">
<div class="row">
<div class="button">1</div>
<div class="button">2</div>
<div class="button">3</div>
</div>
<div class="row">
<div class="button">4</div>
<div class="button">5</div>
<div class="button">6</div>
</div>
<div class="row">
<div class="button" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
.row {
display: flex;
}
.button {
flex: 1;
margin: 5px;
border: 1px solid gray;
}
.button#number0 {
flex: 2;
}
.button#colon {
flex: 1;
}
问题: 如图,flex值为2 的子项无法与其他行 flex值为1 子项的边缘对齐
分析: flex容器的剩余空间会先减去flex子项之间的 margin, 然后再去按照伸缩比例进行分配各子项空间。而flex值为2的子项所在的行比其他行少了10px的margin,剩余空间也会比其他行多了10px,故比例1的对应空间也会多于其他行。
参考:
how-to-get-flexbox-to-include-padding-in-calculations
flex-grow-not-sizing-flex-items-as-expected
用户体验思考与flex三坑:元素不均分、溢出不省略和垂直不滚动
解决思路:
使用可明确长度的 flex-basis 属性而不用flex: 1
.button { flex-basis: 33.33%; }
#number0 { flex-basis: calc(66.67% + 10px); }
* { box-sizing: border-box; }
注: 让所有元素 box-sizing: border-box; 目的是让元素整体宽度包含边框, 避免在分配空间时因边框产生计算误差
2.4 其他应用场景
需求场景:多个子元素下, 元素保持等比例宽度, 空间剩余时, 子元素不撑满, 空间不足时, 仍保持等比例宽度, 不会被压缩, 而是出现滚动条
解决思路:各子项设置 flex: 0 0 25%;