用 flex 布局时遇到一个问题,原本想让 flex 子元素平均宽度显示,却因为子元素里面的内容宽度把其中一个子元素宽度撑开导致宽度不一致。先看代码:

.flex-box{
  width: 500px;
  display: flex;
  padding: 10px;
  border: 2px solid orange;
}
.flex-box div{
  flex: 1;
  border: 1px solid black;
}
.flex-box div p{
  white-space: nowrap;
}
<div class="flex-box">
  <div >
    <p>普通文本</p>
  </div>
  <div >
    <p>超长不换行的文本,超长不换行的文本,超长不换行的文本,超长不换行的文本,超长不换行的文本。</p>
  </div>
</div>

期望得到以下的效果:
image.png

但实际的效果却是下面这样,无法达到两列宽度平均的效果:
image.png

查了一下资料,发现了原因, W3C 规范定义:
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.

浏览器默认为 flex item 设置了 "min-width: auto;min-height: auto", 即 flex 子元素的最小宽度高度不能小于其内容的宽度高度。

通过设置 min-width: 0;, 覆盖掉这个默认设置,flex-shrink 属性就能生效了:

.flex-box{
  width: 500px;
  display: flex;
  padding: 10px;
  border: 1px solid red;
}
.flex-box div{
  min-width: 0; // 新增行
  flex: 1;
  border: 1px solid black;
}
.flex-box div p{
  white-space: nowrap;
}

效果就正常了(由于业务需要有些地方不能用 overflow: hidden;):image.png

但也有一种情况就是即使设置了 min-width: 0, flex-shrink 也不起作用,原因是多层嵌套 flex, 需要把最外层的 flex item 也设置 min-width: 0; 才能起作用。

最后发现有一种简单粗暴的方法,就是直接设置 flex item 设置:width: 0; 不受多层嵌套 flex 的影响。

.flex-box{
  width: 500px;
  display: flex;
  padding: 10px;
  border: 1px solid red;
}
.flex-box div{
  width: 0; // 新增修改行
  flex: 1;
  border: 1px solid black;
}
.flex-box div p{
  white-space: nowrap;
}

参考资料:
https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size?answertab=votes#tab-top
https://www.w3.org/TR/css-flexbox-1/#min-size-auto
https://juejin.cn/post/6974356682574921765#comment