侧边栏壁纸
博主头像
一笑痕

人生若只如初见,
是可喜亦或者是可悲?

  • 累计撰写 141 篇文章
  • 累计收到 7 条评论

省略号一直不出现,卡在中间那层的 min-width

2026-9-28 / 0 评论 / 5 阅读

省略号一直不出现,卡在中间那层的 min-width

一行里放两件东西:左边是可能很长的标题,右边是固定宽的按钮。标题太长了要截断,加省略号。样式写得很标准,三行都在:

.title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

结果右边那个按钮被推到看不见的地方,整行还能横向滚。把标题换成短句子,按钮立刻回到该在的位置。问题不在那三行,三行都没写错。

一样的三行 CSS,只换掉外层的结构

搭了一个最小页面来隔离这件事:外层是宽 320px 的 flex 行,右侧一个 flex: 0 0 64px 的固定宽兄弟元素,中间放标题。四种结构,量同一批数字。

浏览器:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/154.0.0.0 Safari/537.36
页面宽度固定 320px 的 flex 行,右边一个 64px 的固定宽兄弟元素
取到测量结果:true

情形一和情形二用的是同一套 CSS 类,差别只在元素层级:情形一的标题元素自己就是 flex 项,情形二的标题外面多包了一层普通 div,中间那层才是 flex 项。前者正常出省略号,后者把行撑到溢出 116px,一个字都没截。

差的那 116 像素是从哪里来的

320px 的容器,扣掉 64px 的固定宽兄弟和边框内边距,留给标题的位置是 250px。标题那句的自然宽度量出来是 367.77px,多出 117.77px 顶到行外面,加上边框和 padding 正好对上溢出的 116px。

数字里最能说明问题的是情形二的这两个:中间层宽 367.77,文本元素 clientWidth 368,两个数一样大,说明文本元素拿到的完整宽度就是它的自然宽度,它从来没有被压缩过。没有压缩,就没有溢出可截,text-overflow: ellipsis 也就没有可显示省略号的机会。

情形三只做了一件事:给中间那一层加 min-width: 0。中间层宽度立刻落到 250px,文本元素 clientWidth 变成 250、scrollWidth 还是 368,省略号出现了。

原因是 flex 项的 min-width 默认值不是 0,是 auto,而 auto 在这里的含义是「不小于内容的最小宽度」。规范里管这个叫自动最小尺寸。情形一没这个问题,因为标题元素自己就是 flex 项,同时它带着 overflow: hidden,自动最小尺寸会自动归零,压得下来。多包一层之后,带 overflow: hidden 的变成了里面的文本元素,而待压缩的那一层是外面那张没写任何 overflow 的 div。

overflow 写错地方也能碰巧修好

情形四是另一条路:不给中间层写 min-width: 0,只把 overflow: hidden 补到它身上。宽度同样落到 250px,省略号同样出现,量出来的数字和情形三一模一样。

这条路能成立,逻辑和情形一相同:那一层的 overflow 不再是 visible,自动最小尺寸就归零了。问题是它的意图是错的,加 overflow: hidden 的念头通常是「那我把多余的裁掉」,而这一层本来不需要裁东西,该裁的活已经由里面的文本元素干了。哪天有人来清理,看到这一层既没有滚动也没有溢出,顺手把这行删掉,省略号就又没了。

min-width: 0 写的意图是「这一层可以被压到零宽」,说的正是要做的事。修法上我倾向于这一条,而不是顺手补一个 overflow: hidden 把副作用当方案用。

量三个数字就能分清是哪种坏

这类问题的排查不需要猜,取一个元素量三个数就够了:外层的 getBoundingClientRect().width、文本元素的 clientWidth、文本元素的 scrollWidth。

  • clientWidth 等于 scrollWidth:元素没被限制,宽度就是内容的自然宽度,问题在压缩没生效。
  • clientWidth 明显小于 scrollWidth:压缩生效了,问题在别处,可能是 text-overflow 没写,或者元素不是块级(行内元素上这两行样式都不起作用)。
  • 外层还多量一个 scrollWidth:大于 clientWidth 就说明它自己在横向溢出,被撑破的是这一层。
== 结论行 ==
  情形一 文本元素即 flex 项           溢出     0px  省略号 true
  情形二 没写 min-width 的中间层      溢出   116px  省略号 false
  情形三 中间层 min-width:0        溢出     0px  省略号 true
  情形四 中间层只加 overflow:hidden  溢出     0px  省略号 true

上面四行是同一份页面的最终读数,true 表示省略号确实出现了。这一组数字比肉眼看截图可靠:截图上「省略号没出现」和「省略号出现了但只有两个点」很难分清,宽度差多少是确定的。

真机上只在 Chromium 里量过,Safari 和 Firefox 没跑。这套最小尺寸的算法是通行行为,但换浏览器第一次上线时,还是照着那三个数字在自己的页面上量一遍更保险。

顺手会碰到的两种同类结构

表格单元格里的单行省略是同一个坑的另一副面孔。table-layout: auto 下单元格宽度由内容决定,给单元格里的文本加省略号同样无效,得先把 table-layout: fixed 打开,列宽有确定来源之后截断才有意义。

从 flex 换成 grid 之后写法变了,坑没变:grid-template-columns: 1fr 64px 里的 1fr 最小也是 auto,要写 minmax(0, 1fr) 才允许压缩到零。左右分栏的列表从 flex 改到 grid 时,这个写法最容易漏,症状和前面那 116px 的溢出一样。

    🤞 分享