本篇博客将以 “ flex 布局里设置 auto 的区块怎么让文案超出省略的问题” 作为切入点,来分析一下 flex 布局里面各子项的具体长度到底怎么计算。
【资料图】
我们有一个 H5 项目,类似于微信的通讯录界面,前面是头像,后面是昵称。
所以我们一开始的代码是这么写的:
pic 00000000000000000000
pic 00000000000000000000 用人话来翻译一下这段代码,就是:
第一个 flex 布局子项占 100,且有剩余不占,有超出不减;
第二个 flex 布局子项自由适配,有剩余就占,有超出就减。
所以就达到了头像恒占 100,剩下部分占据剩余宽度的效果。
这个时候,我们需要关心的还有一个问题,就是昵称的长度问题,如果昵称长度太长了我们需要省略一下。所以我们对代码做了如下修改:
pic 00000000000000000000000000000000000000000000000000000000
pic 00000000000000000000000000000000000000000000000000000000 但 flex 布局的 flex-basis 设置为 auto 后,省略却不会如期生效。
这个时候可以用三种方法去解决这个问题:
设置第二个 flex 布局子项 width 为小于剩余宽度的值,由于剩余宽度不好确定,设置为0最保险
pic 00000000000000000000000000000000000000000000000000000000
pic 00000000000000000000000000000000000000000000000000000000 设置第二个 flex 布局子项 min-width 为小于剩余宽度的值,由于剩余宽度不好确定,设置为0最保险
pic 00000000000000000000000000000000000000000000000000000000
pic 00000000000000000000000000000000000000000000000000000000 设置第二个 flex 布局子项 overflow为 hidden(实际上设置 scroll、auto 都是可以的,但滚动,多少有些奇怪吧)
pic 00000000000000000000000000000000000000000000000000000000
pic 00000000000000000000000000000000000000000000000000000000 在解释这些设置为什么能解决这个问题之前,先来重新认识一下 flex 布局,毕竟长时间使用各个 UI 组件库的 Grid 后,自己也部分丧失了对弹性布局的理解。
我们这里不去讨论 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-grow
、flex-shrink
两个扩缩相关的。
这个属性规定了 flex 布局子项在 flex 容器中分配剩余空间的相对比例,这个属性的默认值为0。
剩余空间是 flex 容器的大小减去所有 flex 项的大小加起来的大小。如果所有的 flex 布局子项的 flex-grow 系数加起来小于等于1,则剩余空间直接用 flex-grow 系数进行分配(有空余也不会接着分配);否则把 flex-grow 系数当成权重进行分配。
|- 140px -| |- 160px -| \[\text{第一个子项(青色)的宽度:}W1 = \text{子项的初始大小:}100 + \text{剩余宽度:}200 * \text{flex-grow:}0.2 = 140 \\\text{第二个子项(棕色)的宽度:}W2 = \text{子项的初始大小:}100 + \text{剩余宽度:}200 * \text{flex-grow:}0.3 = 160\]
|- 180px -| |- 220px -| \[\text{第一个子项(青色)的宽度:}W1 = \text{子项的初始大小:}100 + \text{剩余宽度:}200 * \text{比例:}\frac{2}{2 + 3} = 140 \\\text{第二个子项(棕色)的宽度:}W2 = \text{子项的初始大小:}100 + \text{剩余宽度:}200 * \text{比例:}\frac{3}{2 + 3}> = 160\]这个属性规定了 flex 布局子项在 flex 容器中的收缩规则,这个属性的默认值为1。
flex 布局子项在原始宽度之和大于容器的时候才会发生收缩。与 flex-grow 一样,如果所有的 flex 布局子项的 flex-shrink 系数加起来小于等于1,则超出部分直接用 flex-shrink 系数进行缩减(有超出也不会接着缩减);否则把 flex-shrink 系数当成权重进行超出部分的缩减。
\[\text{第一个子项(青色)的宽度:}W1 = \text{子项的初始大小:}300 - \text{超出宽度:}200 * \text{flex-shrink:}0.2 = 260 \\\text{第二个子项(棕色)的宽度:}W2 = \text{子项的初始大小:}300 - \text{超出宽度:}200 * \text{flex-shrink:}0.3 = 240\]
\[\text{第一个子项(青色)的宽度:}W1 = \text{子项的初始大小:}300 - \text{超出宽度:}200 * \text{比例:}\frac{2}{2 + 3} = 220 \\\text{第二个子项(棕色)的宽度:}W2 = \text{子项的初始大小:}300 - \text{超出宽度:}200 * \text{比例:}\frac{3}{2 + 3} = 180\]flex-basis: auto
的计算规则flex-basis 之所以单独介绍,是因为他是我们今天讨论的问题围绕的关键CSS属性
flex-basis 大部分时候是可以等同于 width的(flex-basis 的优先级比width高),但设置为 auto 的时候是比较特殊的,而且有较为复杂的发展历史。
备注:简史
- 最初,"flex-basis:auto" 的含义是 "参照我的
width
和height
属性".- 在此之后,"flex-basis:auto" 的含义变成了自动尺寸,而 "main-size" 变成了 "参照我的
width
和height
属性"。实际执行于 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 和设置 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 可以让文案省略生效了。
我们已经知道 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 的子项默认情况如下代码:
10000000000000000000000000000000000000000000000000000000000000000000
10000000000000000000000000000000000000000000000000000000000000000000 开发者需要用 min-width:0
覆盖 min-width: fit-content
。
CSS 的设计还是有其深奥的地方,平时过于依赖UI组件库果然是不行呢~
杭齿前进:独立董事关于第六届董事会第二次会议相关事项的专项说明及独立意见
全年服务超5亿用户,出具91亿张保单,实现总保费人民币236 5亿元,同比增长16 1%……近日,众安保险发布2022年度业绩报告,一组组数据背后,凸
1、焦距是光学系统中光线会聚或发散的量度,指平行光入射时,透镜光学中心到光线会聚焦点的距离。具有短焦距的光学系统比具有长
绿色中国北京4月11日电(融媒体记者耿国彪)4月11日,记者从国家林草局获悉,4月9日至11日,我国发生一次大范围沙尘
(人民日报健康客户端记者王振雅)辉瑞新冠疫苗一年卖出378亿美元, "药王 "修美乐再创历史新高卖出212亿美元……随着全球药企发布财报数据,全