CSS杂谈——flex布局里面的auto到底多长

Posted 轩_雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSS杂谈——flex布局里面的auto到底多长相关的知识,希望对你有一定的参考价值。

本篇博客将以 “ flex 布局里设置 auto 的区块怎么让文案超出省略的问题” 作为切入点,来分析一下 flex 布局里面各子项的具体长度到底怎么计算。

从需求出发谈 flex 布局

我们有一个 H5 项目,类似于微信的通讯录界面,前面是头像,后面是昵称。

所以我们一开始的代码是这么写的:

<div >
    <div >pic</div>
    <div >
        00000000000000000000
    </div>
</div>
<!-- 实际开发我们是用antd来实现的,这里写html只算是用于分析的伪代码。-->
<!-- 然后为了显示效果border设置得十分明显,宽度也固定为400(实际开发还是要适配各个机型的宽度的)。-->
pic
00000000000000000000

用人话来翻译一下这段代码,就是:

第一个 flex 布局子项占 100,且有剩余不占,有超出不减;

第二个 flex 布局子项自由适配,有剩余就占,有超出就减。

所以就达到了头像恒占 100,剩下部分占据剩余宽度的效果。

这个时候,我们需要关心的还有一个问题,就是昵称的长度问题,如果昵称长度太长了我们需要省略一下。所以我们对代码做了如下修改:

<div >
    <div >pic</div>
    <div >
    	<div >
            00000000000000000000000000000000000000000000000000000000
        </div>
    </div>
</div>
pic
00000000000000000000000000000000000000000000000000000000

但 flex 布局的 flex-basis 设置为 auto 后,省略却不会如期生效。

这个时候可以用三种方法去解决这个问题:

  1. 设置第二个 flex 布局子项 width 为小于剩余宽度的值,由于剩余宽度不好确定,设置为0最保险

    <div >
        <div >pic</div>
        <div >
        	<div >
             00000000000000000000000000000000000000000000000000000000
            </div>
        </div>
    </div>
    
    pic
    00000000000000000000000000000000000000000000000000000000
  2. 设置第二个 flex 布局子项 min-width 为小于剩余宽度的值,由于剩余宽度不好确定,设置为0最保险

    <div >
        <div >pic</div>
        <div >
        	<div >
             00000000000000000000000000000000000000000000000000000000
            </div>
        </div>
    </div>
    
    pic
    00000000000000000000000000000000000000000000000000000000
  3. 设置第二个 flex 布局子项 overflow为 hidden(实际上设置 scroll、auto 都是可以的,但滚动,多少有些奇怪吧)

    <div >
        <div >pic</div>
        <div >
        	<div >
             00000000000000000000000000000000000000000000000000000000
            </div>
        </div>
    </div>
    
    pic
    00000000000000000000000000000000000000000000000000000000

在解释这些设置为什么能解决这个问题之前,先来重新认识一下 flex 布局,毕竟长时间使用各个 UI 组件库的 Grid 后,自己也部分丧失了对弹性布局的理解。

Flex 布局的扩缩策略

我们这里不去讨论 flex 布局中 wrap 的部分,也只以水平方向的 flex 布局为例。尽量先简单地理解,如果大家对 flex 布局想要了解得更深,可以阅读 w3c 关于 CSS Flexible Box Layout Module Level 1 (w3.org) 的最新内容。

我们先了解一下 flex 这个决定布局扩缩策略的 CSS 属性。

flex 属性是以下 CSS 属性的简写:

  • flex-grow
  • flex-shrink
  • flex-basis
.flex-container 
	flex: 0 0 100px

就是代表

.flex-container 
	flex-grow: 0;
	flex-shrink: 0;
	flex-basis: 100px;

我们这里仅讨论三值语法,关于flex单值语法、双值语法的与flex-grow、flex-shrink、flex-basis的对应关系不在这里展开讨论,详细可以看 flex - CSS:层叠样式表 | MDN (mozilla.org) 这篇MDN文档。

接下来,先介绍一下flex-growflex-shrink两个扩缩相关的。

flex-grow

这个属性规定了 flex 布局子项在 flex 容器中分配剩余空间的相对比例,这个属性的默认值为0。

剩余空间是 flex 容器的大小减去所有 flex 项的大小加起来的大小。如果所有的 flex 布局子项的 flex-grow 系数加起来小于等于1,则剩余空间直接用 flex-grow 系数进行分配(有空余也不会接着分配);否则把 flex-grow 系数当成权重进行分配。

flex-grow 系数加起来小于等于1

<div >
    <div ></div>
    <div ></div>
</div>
|- 140px -|
|- 160px -|

\\[\\text第一个子项(青色)的宽度:W1 = \\text子项的初始大小:100 + \\text剩余宽度:200 * \\textflex-grow:0.2 = 140 \\\\ \\text第二个子项(棕色)的宽度:W2 = \\text子项的初始大小:100 + \\text剩余宽度:200 * \\textflex-grow:0.3 = 160 \\]

flex-grow 系数加起来大于1

<div >
    <div ></div>
    <div ></div>
</div>
|- 180px -|
|- 220px -|

\\[\\text第一个子项(青色)的宽度:W1 = \\text子项的初始大小:100 + \\text剩余宽度:200 * \\text比例:\\frac22 + 3 = 140 \\\\ \\text第二个子项(棕色)的宽度:W2 = \\text子项的初始大小:100 + \\text剩余宽度:200 * \\text比例:\\frac32 + 3> = 160 \\]

flex-shrink

这个属性规定了 flex 布局子项在 flex 容器中的收缩规则,这个属性的默认值为1。

flex 布局子项在原始宽度之和大于容器的时候才会发生收缩。与 flex-grow 一样,如果所有的 flex 布局子项的 flex-shrink 系数加起来小于等于1,则超出部分直接用 flex-shrink 系数进行缩减(有超出也不会接着缩减);否则把 flex-shrink 系数当成权重进行超出部分的缩减。

flex-shrink 系数加起来小于等于1

<div >
    <div ></div>
    <div ></div>
</div>

\\[\\text第一个子项(青色)的宽度:W1 = \\text子项的初始大小:300 - \\text超出宽度:200 * \\textflex-shrink:0.2 = 260 \\\\\\text第二个子项(棕色)的宽度:W2 = \\text子项的初始大小:300 - \\text超出宽度:200 * \\textflex-shrink:0.3 = 240 \\]

flex-shrink 系数加起来大于1

<div >
    <div ></div>
    <div ></div>
</div>

\\[\\text第一个子项(青色)的宽度:W1 = \\text子项的初始大小:300 - \\text超出宽度:200 * \\text比例:\\frac22 + 3 = 220 \\\\\\text第二个子项(棕色)的宽度:W2 = \\text子项的初始大小:300 - \\text超出宽度:200 * \\text比例:\\frac32 + 3 = 180 \\]

flex-basis: auto 的计算规则

flex-basis 之所以单独介绍,是因为他是我们今天讨论的问题围绕的关键CSS属性

flex-basis 大部分时候是可以等同于 width的(flex-basis 的优先级比width高),但设置为 auto 的时候是比较特殊的,而且有较为复杂的发展历史。

备注: 简史

  • 最初,"flex-basis:auto" 的含义是 "参照我的widthheight属性".
  • 在此之后,"flex-basis:auto" 的含义变成了自动尺寸,而 "main-size" 变成了 "参照我的widthheight属性"。实际执行于 bug 1032922.
  • 然后呢,这个更改又在 bug 1093316 中被撤销了,所以 "auto" 变回了原来的含义; 而一个新的关键字 \'content\' 变成了自动尺寸。 (bug 1105111 包括了增加这个关键字).

不过这个历史了解一下就好,它跟我们今天讨论的问题并没有关系。当我们没有给 flex 布局子项设置width时,flex-basis: auto由内部的content决定宽度,和flex-basis: content是一样的。

在上面,我们通过三种方法,让 flex-basis 为 auto 的 flex 布局子项文案省略可以生效。

设置 flex 布局子项 width 为 0,让宽度的初始值为 0,再基于 flex-grow 扩张,而不是以子项的 content 宽度为准,从而保障宽度不溢出,这听起来很好理解。

但是设置 flex 布局子项 overflow 为 hidden、设置 min-width 为 0,从而让宽度不以子项的 content 宽度为准,这听起来就不是一个很好理解的做法。

设置 flex 布局子项 overflow 为 hidden

因为设置 flex 布局子项 overflow 为 hidden 和设置 min-width 为 0 是一个道理,我们先来看看设置 overflow 为 hidden 是怎么等同设置 min-width 为 0 的。

为此,我们需要先阅读一下 CR-css-flexbox-1-20181119 的 4.5节 Automatic Minimum Size of Flex Items

To provide a more reasonable default minimum size for flex items, the used value of a main axis automatic minimum size on a flex item that is not a scroll container is a content-based minimum size; for scroll containers the automatic minimum size is zero, as usual.

从这段话可以得出设置 overflow 为 scroll、auto 可以让 min-width 为 0,所以设置 overflow 为 scroll 和设置 min-width 为 0 在宽度计算的影响方面是等效的。那设置 overflow 为 hidden 呢?

我们来看一下 CR-css-flexbox-1-20181119 从 2016 年之后的处于候选推荐阶段的一些东西 Changes since the 1 March 2016 CR

value to be easier to understand. ([Issue 9](CSS Flexible Box Layout Level 1 Disposition of Comments for 2016-03-01 CR (csswg.org)))

On a flex item whose overflow is visible in the main axis, when specified on the flex item’s main-axis min-size property, the following table gives the minimum size … specifies an automatic minimum size.

In general, the automatic minimum size … defined below:

这里的意思就是为了方便理解,不再是说 overflow 设置为滚动才会使 min-width 为 0,而是只有 overflow 设置为 visible 的时候,min-width 为 auto,其他时候都是 0。一般来讲,有相当部分的文档会在候选推荐阶段就得到浏览器厂商的认可,并用于实践。所以,现在大多数的浏览器也是 overflow 不为 visible 时 min-width 为 0。

设置 flex 布局子项 min-width 为 0

接下来就是讨论为什么设置 flex 布局子项 min-width 为 0 可以让文案省略生效了。

我们已经知道 overflow 为 visible 时,min-width 为 auto,所以一般情况下,min-width 都为 auto。而由于弹性布局特有的扩缩容忍度,flex 布局子项的大小是可以延伸到弹性盒子外的。CR-css-flexbox-1-2018111 也写到了,如果 min-width 为 auto,flex 布局子项就会基于他的 content 去计算自己的最小宽度。

For the purpose of calculating an intrinsic size of the box (e.g. the box’s min-content size), a content-based minimum size causes the box’s size in that axis to become indefinite (even if e.g. its width property specifies a definite size). Note this means that percentages calculated against this size will behave as auto.

这个特性导致最小宽度如果超出原本他可以占据的空间,而 flex-shrink 的设置又受最小宽度的限制不能回缩,flex 布局子项就会溢出。

而省略文本由于设置了white-space: nowrap,导致空格或者其他分割、全角符号不能换行,此时文案越长,flex 布局子项的content越宽,flex 布局子项随着溢出,没有了外边的限制,内部也就失去了省略的必要。

In particular, if flex sizing is being used for a major content area of a document, it is better to set an explicit font-relative minimum width such as min-width: 12em. A content-based minimum width could result in a large table or large image stretching the size of the entire content area into an overflow zone, and thereby making lines of text gratuitously long and hard to read.

CR-css-flexbox-1-2018111 文档也说明了这样的特性会导致溢出的出现,需要开发者去指定一个最小宽度,所以指定最小宽度是一个官方的,合理的解决方案。

简单理解

如果长篇大段不好理解,其实有一个比较奇特的类比可以说明问题。一般来说,flex 布局设置 flex-basis 为 auto 的子项默认情况如下代码:

<div >
    <div >
        <div >10000000000000000000000000000000000000000000000000000000000000000000</div>
    </div>
</div>
10000000000000000000000000000000000000000000000000000000000000000000

开发者需要用 min-width:0 覆盖 min-width: fit-content

CSS 的设计还是有其深奥的地方,平时过于依赖UI组件库果然是不行呢~

flex 1与flex auto

flex意为"弹性布局"

这次主要探究的是flex:1与flex:auto的区别,flex是flex-growflex-shrink 和 flex-basis的简写,默认值为0 1 auto

首先上代码:

技术图片

上面为flex的基础布局,效果如下:

技术图片

下来看看:flex:1的效果:

 技术图片

技术图片

再下来看看flex:auto的效果:

技术图片

技术图片

基本已经明白了:

flex:1相当于 flex-grow:1flex-shrink:1 , flex-basis:0% (子元素宽度 = 父级宽度/3)

flex:auto相当于flex-grow:1flex-shrink:1 , flex-basis:auto (子元素宽度 = 子元素宽度 +(父级宽度-子元素宽度之和/3)

flex:none相当于flex-grow:0flex-shrink:0 , flex-basis:auto

 

以上是关于CSS杂谈——flex布局里面的auto到底多长的主要内容,如果未能解决你的问题,请参考以下文章

[CSS七分钟系列]都1902年了,还不知道用margin:auto给flex容器内元素分组?

Flex 项目属性:flex 布局示例

css3之flex

CSS3-flex弹性布局之flex属性

CSS布局 , 单列宽度固定,另一列自适应。

flex布局