flex 子项不肯缩小?那是 min-width: auto 在按规范办事

布局长这样:左边 48px 头像,右边文字区 flex: 1。放一段普通中文没事,一旦进来一条没有空格的 URL 或者长英文单词,整个容器横着撑出去,页面开始横向滚动。

.media { display: flex; gap: 12px; }
.media .avatar { flex: 0 0 48px; }
.media .body   { flex: 1; }          /* 想让它吃掉剩余空间,并且能缩 */

直觉是”flex-shrink 默认为 1,应该能缩”,但怎么都不缩。

规范里的一行字

CSS Flexbox 里,flex item 的 min-width 初始值是 auto。这个 auto 在主轴上会解析成 min-content——内容缩到最小可能宽度的那一档。一条没有断点的长串,它的 min-content 就是整串本身。

而 flex-shrink 再怎么缩,也不能小于 min-width。两者叠加的结果:子项被内容焊死在原地。

规范里还有个例外:当 overflow 不是 visible(即 hidden / auto / scroll / clip)时,automatic minimum size 会退化成 0。这解释了那个流传很广但很少被讲清的经验——”加个 overflow: hidden 就好了”,它治好的正是这一条。

三种写法,挑一种

/* 1. 显式关掉 auto,最直接,副作用最小 */
.media .body { flex: 1; min-width: 0; }

/* 2. 借那个规范的例外条款 */
.media .body { flex: 1; overflow: hidden; }
/*    注意:这会把溢出的内容裁掉,不是所有场景都能接受 */

/* 3. 让长串本身可以断行,从"内容最小宽度"这一侧解决 */
.media .body { flex: 1; overflow-wrap: anywhere; }

我一般用第一种。min-width: 0 的语义就是”允许缩到零”,写出来之后阅读的人也知道这里为什么这么写——比一个来历不明的 overflow: hidden 清楚。

同一个坑的两个变种

省略号不显示。 text-overflow: ellipsis 要生效需要三个条件同时成立:overflow: hidden、white-space: nowrap、以及——在 flex 子项里——min-width: 0。很多”省略号没效果”的问题,前两个都对,就差最后一个。

.cell {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

Grid 里完全一样。 grid item 的 min-width / min-height 也是 auto。所以 grid-template-columns: 1fr 遇到长内容也会溢出,要写 minmax(0, 1fr)——它跟 min-width: 0 是同一个问题的两种写法,只是作用在轨道上。

/* 会被内容撑破 */
grid-template-columns: 1fr 1fr 1fr;

/* 不会 */
grid-template-columns: repeat(3, minmax(0, 1fr));

顺带一句

flex: 1 是 flex-grow:1; flex-shrink:1; flex-basis:0% 的缩写。如果想”按内容宽度、不参与分配”,就写 flex: 0 0 auto;”固定 48px、不放大不缩小”就是 flex: 0 0 48px。把三个值都写出来,比用缩写更容易一眼看懂意图——尤其是三个月后回来看的自己。

← 返回技术笔记