flex:0 flex:1 flex:none flex:auto应该在什么场景下使用?

这篇文章发布于 2020年10月6日,星期二,13:21,归类于 CSS相关。 阅读 3233 次, 今日 84 次 5 条评论

 

一、推荐使用flex缩写语法

CSS官方文档明确推荐flex属性使用缩写语法,描述如下所示:

Authors are encouraged to control flexibility using the flex shorthand rather than with its longhand properties directly, as the shorthand correctly resets any unspecified components to accommodate common uses.

大致意思是,建议使用单值缩写,而不是完整的3个属性值,因为单值属性所对应的flex计算值根据开发者日常最常用的使用进行了优化。

这句话很多人并不知道什么意思,这个说来话长,想想还是讲一下吧。

flex属性是flex-growflex-shrinkflex-basis这3个CSS属性的缩写,如果不清楚,可以参见我之前这篇口碑热文“CSS flex属性深入理解”。

按照以往的经验,flex属性只有一个值的时候,另外缺省的值应该使用默认值才对,但是flex属性并不是这样的。

我们可以对比CSS border属性。

CSS border属性是border-widthborder-styleborder-color这3个CSS属性的缩写,当border属性设置了1个值或2个值的时候,剩下的属性值一定是默认值,例如:

  • border:2px等同于border:2px none currentColor,也就是此时border-style是默认值noneborder-color的计算值是当前的色值;
  • border:#fff等同于border:medium none #fff,也就是此时border-width是默认值medium
  • border:solid等同于border:medium solid currentColor

使用下面的代码可以得到flex-basis默认值是autoflex-grow默认值是0flex-shrink默认值是1

console.log(getComputedStyle(document.body).flexGrow);
console.log(getComputedStyle(document.body).flexShrink);
console.log(getComputedStyle(document.body).flexBasis);

实际运行效果如下:
Chrome和Firefox浏览器获取的flex子属性的默认值示意

然后再看下flex缩写属性的计算值,就会发现不一样的事情:

  • flex:1等同于flex:1 1 0%flex:1 2等同于flex:1 2 0%,即flex-basis使用的不是默认值auto,而是使用的0%
  • flex:100px等同于flex:1 1 100px,即flex-grow使用的不是默认值0,而是使用的1

这就是上面提到的flex属性站在实用主义的角度对缩写属性的计算值进行了优化。

然后,还有一个重要原因,flex属性的长语法需要理解深刻,反复使用才能驾驭,门槛比较好,因此,实际开发,如果可以,建议使用flex缩写。

常见的flex缩写有下面这几个,flex:0flex:1flex:noneflex:auto,那各个CSS声明应该在什么场景下使用才正确呢?

二、使用flex缩写语法场景

下表展示了常见的flex属性单值语法对应的flex计算值,涵盖了绝大多数的flex属性的使用场景。

flex单值语法对应的计算值
单值语法 等同于 备注
flex: initial flex: 0 1 auto 初始值,常用
flex: 0 flex: 0 0 0% 适用场景少
flex: none flex: 0 0 auto 推荐
flex: 1 flex: 1 1 0% 推荐
flex: auto flex: 1 1 auto 适用场景少

1. flex:initial基本表现和适用场景

flex:initial等同于设置flex: 0 1 auto,可以理解为flex属性的默认值。

该默认值图形示意如下图所示。

flex属性初始值分解示意

其行为表现文字描述为:

flex容器有剩余空间时尺寸不会增长(flex-grow:0),flex容器尺寸不足时尺寸会收缩变小(flex-shrink:1),尺寸自适应于内容(flex-basis:auto)(行为类似fit-content)。

举个例子,我们给flex容器设置深红色的虚线框,如果此时flex子项(设置深天蓝色轮廓)的内容都比较少,就会有如下图所示的效果,剩余空间依然保留。

flex子项内容较少时候的尺寸表现

相关CSS代码和HTML代码如下所示:

.container {
    display: flex;
    border: 2px dashed crimson;
}
.container item {
    border: 2px solid deepskyblue;    
}
<div class="container">
    <item>范张</item>
    <item>范鑫</item>
    <item>范旭</item>
    <item>范帅</item>
    <item>范哥</item>
</div>

如果子项内容很多,由于flex-shrink:1,因此,会缩小,表现效果就是文字换行,效果如下图所示。

flex子项内容较多时候的尺寸表现

'initial'是CSS中的一个全局关键字,表示CSS属性的初始值,通常用来还原已经设置的CSS属性。因此日常开发不会专门设置flex:initial声明,但是不设置并不是说flex默认属性值用的不多。

flex:initial适用场景

flex:initial声明适用于下图所示的布局效果。

适合flex:initial声明的布局轮廓图示意

上图所示的布局效果常见于按钮、标题、小图标等小部件的排版布局,因为这些小部件的宽度都不会很宽,水平位置的控制多使用justify-contentmargin-left:auto/margin-right:auto实现。

除了上图所示的布局效果外,flex:initial声明还适用于一侧内容宽度固定,另外一侧内容宽度任意的两栏自适应布局场景,布局轮廓如图下图所示(点点点表示文本内容)。

适合flex:initial声明的两栏自适应布局轮廓图示意

此时,无需任何其他Flex布局相关的CSS设置,只需要容器元素设置display:flex即可。

总结下就是那些希望元素尺寸收缩,同时元素内容万一较多又能自动换行的场景可以不做任何flex属性设置。

2. flex:0和flex:none的区别和各自适用场景

flex:0等同于设置flex: 0 0 0%flex:none等同于设置flex: 0 0 auto

这两个值的图形示意如下图所示。

flex:0和flex:none分解示意

从上可以看出flex:0flex:none对应的flex-growflex-shrink属性值均是0,因此两者都会有如下的行为描述:

元素尺寸不会弹性增大、也不会弹性变小,也就是元素不再具有弹性。

flex-basis:0%flex-basis:auto有什么区别呢?

  • flex-basis:0%表示固定尺寸是0,由于元素不具有弹性,因此,设置flex:0的元素的最终尺寸表现为最小内容宽度;
  • flex-basis:auto表示固定尺寸由内容决定,由于元素不具有弹性,因此,元素内的内容不会换行。但是,注意,不会换行并不表示设置flex:none的元素最终尺寸表现就是最大内容宽度,如果外部尺寸不足,flex:none有可能实际的尺寸是最小内容尺寸;

举个例子,设置每个flex子项有足够多的内容,HTML代码如下所示:

<h4>flex:0</h4>
<div class="container flex-0">
    <item>范张范张范张</item>
    <item>范鑫范鑫范鑫</item>
    <item>范旭范旭范旭</item>
    <item>范帅范帅范帅</item>
    <item>范哥范哥范哥</item>
</div>
<h4>flex:none</h4>
<div class="container flex-none">
    <item>范张范张范张</item>
    <item>范鑫范鑫范鑫</item>
    <item>范旭范旭范旭</item>
    <item>范帅范帅范帅</item>
    <item>范哥范哥范哥</item>
</div>

然后对flex子项分别设置flex:0flex:none,CSS代码如下所示:

.container {
    display: flex;
}
.flex-0 item {
    flex: 0;
}
.flex-none item {
    flex: none;
}

结果如图下图所示:

flex:0和flex:none的布局效果示意

可以看到应用了flex:0的元素全部高高耸起,一柱擎天,表现为最小内容宽度;而应用了flex:none的元素则无视容器的尺寸限制,直接溢出容器,没有换行,表现为最大内容宽度。

适合使用flex:0的场景

由于应用了flex:0的元素表现为最小内容宽度,因此,适合使用flex:0的场景并不多,除非元素内容的主体是替换元素,此时文字内容就会庇护在替换元素的宽度下从而不会出现“一柱擎天”的排版效果。

该适用场景的布局示意如下图所示。

适用于flex:0的布局轮廓示意图

其中上图左侧部分的矩形表示一个图像,图像下方会有文字内容不定的描述信息,此时,左侧内容就适合设置flex:0,这样,无论文字的内容如何设置,左侧内容的宽度都是图像的宽度。

适合使用flex:none的场景

当flex子项的宽度就是内容的宽度,且内容永远不会换行,则适合使用flex:none,这个场景比flex:0适用的场景要更常见。

例如列表右侧经常会有一个操作按钮,对于按钮元素而言,里面的文字内容一定是不能换行的,此时,就非常适合设置flex:none,例如下面这个例子,示意了按钮使用了flex:none之后的布局变化,HTML和CSS代码如下所示:

<div class="item">
    <img src="1.jpg">
    <p>右侧按钮没有设置flex:none,表现为最小内容宽度。</p>
    <button>按钮</button>
</div>
<div class="item">
    <img src="1.jpg">
    <p>右侧按钮设置了flex:none,按钮正常显示了。</p>
    <button class="none">按钮</button>
</div>
.container {
    display: flex;
    padding: .5rem;
    border: 1px solid lightgray;
    background-color: #fff;
}
img {
    width: 3rem; height: 3rem;
    margin-right: .5rem;
}
button {
    align-self: center;
    padding: 5px;
    margin-left: .5rem;
}
.none {
    flex: none;
}

从代码可以看出两段内容的唯一区别就是下面的布局对按钮元素设置了flex:none,结果就有如下图所示的不同的布局效果。

适用于flex:none的对比效果示意图

不仅按钮正常显示了,整个布局会自动适配按钮的尺寸,也就是按钮文字多了,中间的文字内容宽度就会自动减小,整个布局依然是弹性的。

3. flex:1和flex:auto的区别和各自适用场景

flex:1等同于设置flex: 1 1 0%flex:auto等同于设置flex: 1 1 auto

这两个值的图形示意如下图所示。

flex:1和flex:auto分解示意

结合flex属性值的描述,我们可以得出flex:1flex:auto的行为表现:

元素尺寸可以弹性增大,也可以弹性变小,具有十足的弹性,但是flex:1在尺寸不足时会优先最小化内容尺寸,flex:auto在尺寸不足时会优先最大化内容尺寸。

上面的描述可以通过一个例子明白是什么意思,这一次是仅仅设置第1项的文字内容很多,HTML代码如下所示:

<h4>flex:1</h4>
<div class="container flex-1">
    <item>范张范张范张范张范张范张范张范张范张</item>
    <item>范鑫</item>
    <item>范旭</item>
    <item>范帅</item>
    <item>范哥</item>
</div>
<h4>flex:auto</h4>
<div class="container flex-auto">
    <item>范张范张范张范张范张范张范张范张范张</item>
    <item>范鑫</item>
    <item>范旭</item>
    <item>范帅</item>
    <item>范哥</item>
</div>

可以看出两段HTML结构和内容都是一样的,现在,对上下两端HTML设置不同的CSS样式,代码如下所示:

.flex-1 item {
    flex: 1;
}
.flex-auto item {
    flex: auto;
}

结果就会看到如下图所示的布局效果。

flex:1和flex:auto的对比效果示意

上图鲜明地体现了flex:1flex:auto的区别,虽然都是充分分配容器的尺寸,但是flex:1的尺寸表现更为内敛(优先牺牲自己的尺寸),flex:auto的尺寸表现则更为霸道(优先扩展自己的尺寸)。

从某种程度上讲,flex:1的表现神似table-layout:fixedflex:auto的表现神似table-layout:auto

适合使用flex:1的场景

当希望元素充分利用剩余空间,同时不会侵占其他元素应有的宽度的时候,适合使用flex:1,这样的场景在Flex布局中非常的多。

例如所有的等分列表,或者等比例列表都适合使用flex:1或者其他flex数值,适合的布局效果轮廓如下图所示。

flex:1适合用在固定比例的列表中

以及适用于无规律布局中动态内容元素,我们不妨继续使用flex:none那里演示的例子进行说明。

下面这段HTML和CSS代码下的按钮元素是换行显示的(就是前面出现过的按钮不换行的例子的HTML代码)。

<div class="item">
    <img src="1.jpg">
    <p>右侧按钮没有设置flex:none,表现为最小内容宽度。</p>
    <button>按钮</button>
</div>
.container {
    display: flex;
    padding: .5rem;
    border: 1px solid lightgray;
    background-color: #fff;
}
img {
    width: 3rem; height: 3rem;
    margin-right: .5rem;
}
button {
    align-self: center;
    padding: 5px;
    margin-left: .5rem;
}

除了设置<button>元素flex:none以外,在这个例子中,我们还可以设置<p>元素flex:1实现类似的效果。

p {
    flex: 1;
}

结果就有如下图所示,<p>元素设置了flex:1之后,按钮元素正常显示了。

主体动态的文本元素设置flex:1之后的效果对比示意

适合使用flex:auto的场景

当希望元素充分利用剩余空间,但是各自的尺寸按照各自内容进行分配的时候,适合使用flex:auto

flex:auto多用于内容固定,或者内容可控的布局场景,例如导航数量不固定,每个导航文字数量也不固定的导航效果就适合使用flex:auto效果来实现,我做了个很简单的示意,代码如下所示:

<nav class="flex">
  <span>首页</span>
  <span>排行榜</span>
  <span>我的订单</span>
  <span>个人中心</span>
</nav>
nav span {
    flex: auto;
    line-height: 3rem;
    background: #444;
    color: #fff;
    text-align:center;
}
span + span {
    border-left: 1px solid #eee;
}

此时大家就可以看到一个基于内容自动分配宽度的自适应导航效果了,效果如下图所示,文字越多的导航占据的宽度越大,这完全是浏览器自动分配的。

flex:auto实现的基于内容宽度自动分配的导航效果示意

三、最后总结一下

最后总结一下:

  • flex:initial表示默认的flex状态,无需专门设置,适合小控件元素的分布布局,或者某一项内容动态变化的布局;
  • flex:0适用场景较少,适合设置在替换元素的父元素上;
  • flex:none适用于不换行的内容固定或者较少的小控件元素上,如按钮。
  • flex:1适合等分布局;
  • flex:auto适合基于内容动态适配的布局;

以上就是本文内容,写于2020年国庆,部分内容节选自明年会出版的新书《CSS新世界》。

感谢您的阅读,如果您觉得本文内容还不错,欢迎分享。

(本篇完)

分享到:


发表评论(目前5 条评论)

  1. 吊车尾说道:

    flex-basis: 0% 的表现却是 width:auto /想哭

  2. 安达说道:

    学到了!感谢大佬

  3. Miyang说道:

    学到了,感谢大佬分享。

  4. mfk说道:

    flex很适合新闻列表(左标题+右日期)或讨论列表那种(标题+发布人+更新日期)。标题区的宽度随着容器宽度变化。
    再加上text-overflow:elipse绝配。

  5. meepo说道:

    学到了,flex让布局变得简单