flex子元素的flex-shrink与min-width属性

工作中遇到的一个问题,在伸缩容器内,设置的文本溢出省略的样式失效了。经过精简后的代码示例如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 无法溢出省略 -->
<div style="width:150px;display:flex;background:skyblue;">
<div style="flex:1;">
<p style="white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">
这是一段很长又不让换行的文字
</p>
</div>
</div>

<!-- 添加了min-width后,可以溢出省略 -->
<div style="width:150px;display:flex;background:skyblue;">
<div style="flex:1;min-width:0;">
<p style="white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">
这是一段很长又不让换行的文字
</p>
</div>
</div>

这是一段很长又不让换行的文字

这是一段很长又不让换行的文字

遇到问题后,在项目中找到了一处类似的且没问题的代码,发现那里有一个 min-width:0; 的设置,添加上去后即可解决该问题。但始终不清楚为什么,只能隐约感觉和 flex-shrink 有关系。

后面在网上查找了下,还真找到了这个情况,在 CSS 规范内有提到:

By default, flex items won’t shrink below their minimum content size (the length of the longest word or fixed-size element). To change this, set the min-width or min-height property.

CSS Flexible Box Layout Module Level 17.1.1 Basic Values of flex

默认情况下,flex 子元素收缩时,不会低于它们的最小内容的尺寸,这个最小内容尺寸是指文本内容中最长的单词长度或固定尺寸元素。如果要更改这种情况,需要设置 min-widthmin-height 属性。

上面的那个问题就是试图通过 flex:1 来收缩元素的宽度,然后内容设置溢出省略。
flex:1flex: 1 1 0 的简写,即 flex-grow:1;flex-shrink:1;flex-basic:0;
通过上面的规范,我们就知道了,flex-shrink:1 默认情况下不会把元素收缩到低于元素内容的最小宽度,而元素的最小宽度是多少呢?因为 white-space:nowrap 的关系,文本不会换行,它的最小宽度就是全部文本占据的宽度,因此文本内容也就不存在溢出,自然也就没有溢出省略了。

而设置了 min-width:0; 之后,改变了 flex-shrink:1 的默认行为,说明可以通过 flex-shrink 收缩最小宽度到 0。这时候 flex-shrink:1 就可以把元素收缩到与父元素同宽度了,内容也就出现了溢出省略的情况。

其他方法

除了 min-width 外,根据上面引用的 CSS 规范描述来看,其实还有一种方式可以解决上面示例的问题——固定尺寸。给 flex 子元素添加宽度设置 width:100%;,如此它就有了一个与父容器相同宽度的固定尺寸了,这个尺寸还比强制文字不换行之后的文本内容要小,所以此时它的最小尺寸就是这个固定尺寸,同时还符合了文本溢出的条件【内容比尺寸大】。

1
2
3
4
5
6
7
<div style="width:150px;display:flex;background:skyblue;">
<div style="flex:1;width:100%">
<p style="white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">
这是一段很长又不让换行的文字
</p>
</div>
</div>

这是一段很长又不让换行的文字

具体要采用哪种方式可以根据实际情况来。

参考链接

  • Flex items and min-width:0
  • CSS Flexible Box Layout Module Level 1