meteorological 变成了 neteorological?记一次长单词被"削头"的 UI 排查
用户报了个很玄学的 bug:闪卡里的长单词 meteorological 显示成了 neteorological,首字母像被削了头。排查后发现是 flexbox 的经典坑——flex 子项缺 min-w-0,break-words 形同虚设,长单词溢出被 overflow-hidden 裁掉首尾。顺手全库排查出 9 处同根因问题。
meteorological 变成了 neteorological?记一次长单词被"削头"的 UI 排查
用户报了个很"玄学"的 bug:闪卡里的长单词
meteorological显示成了neteorological——首字母 m 被削掉半边,看起来像 n。这背后是 flexbox 一个极易踩、又毫无报错提示的布局坑。
问题现象
安卓用户 ᗜ֊ᗜ(又双叒是这位)反馈:首页闪卡学习里,单词一长就显示不全。meteorological 会变成 neteorological,首字母像被"削头"了。
排查:不是数据错,是布局裁切
第一反应是数据坏了。查库确认单词本身没问题——meteorological 存得好好的。
那就看 UI。闪卡单词的渲染结构长这样:
<Card className="w-full max-w-md ..."> {/* Card 自带 overflow-hidden */}
<div className="flex items-center justify-center gap-3 w-full">
<h2 className="text-4xl font-bold ... break-words">
{currentWord.word}
</h2>
<Button ... /> {/* 固定宽度的喇叭按钮 */}
</div>
</Card>
关键在 CSS 的两个细节:
<h2>是 flex 子项,默认min-width: auto。flex 子项的最小宽度默认是它的内容宽度(min-content),意味着它不允许收缩到比单词还窄。Card有overflow-hidden。单词撑破卡片后,溢出部分被直接裁掉。
于是发生了这样的事:meteorological 在 text-4xl(约 36px)下宽度超过卡片内容区 → 由于 min-width: auto,它不会换行,而是整行溢出 → 卡片把溢出裁掉。
这里有个反直觉的点:外层是 justify-center(居中)。居中布局溢出时,左右两边是对称溢出的——左边也裁、右边也裁。所以 'm' 的左半边没了,看起来像 'n';单词尾部其实也被削掉了一截,只是你没注意到。
为什么 break-words 没生效?
<h2> 上明明写了 break-words(即 overflow-wrap: break-word),为什么没换行?
因为 min-width: auto 根本不给它换行的机会。 overflow-wrap: break-word 只允许"在单词过长时强制断行",但前提是这个 flex 子项允许收缩到小于单词宽度。min-width: auto 意味着子项的最小宽度 = 单词宽度,永远放得下——那就永远不会触发断行,而是直接溢出。
这是 flexbox 的经典坑:flex-1 不等于 min-w-0。flex-1 只设置了 flex-basis: 0%,不影响 min-width;想让它真正能收缩,必须显式加 min-w-0。
修复
把单词换成「允许收缩 + 强制断行」的写法:
<h2 className="text-4xl font-bold ... text-center min-w-0 break-all">
min-w-0:允许 flex 子项收缩到比内容窄,给换行创造条件break-all:强制在任意字符处断行,保证长单词一定折行而不是溢出
顺手全库扫了一遍
既然踩到了,就系统排查了全项目同款模式。判断规则:
truncate不算 bug:它自带overflow:hidden + ellipsis,flex 下能正常收缩出省略号,是刻意的break-words在 flex 子项上且缺min-w-0才危险:这会让断行形同虚设flex-1≠min-w-0:很多人以为 flex-1 就够了,其实不行
最后查出 9 处同根因问题,分了三级:
高(2 处):两个 flashcard 组件(首页全屏 + 弹窗)的单词 h2——就是这次报的 bug,纯同模式。
中(7 处):
- 翻译结果列表的单词(
flex flex-wrap折不断单词) - 忽略单词列表
- 自定义默写历史词
- 分组名
- AI 翻译结果(
pre-wrap也折不断单词) - 分享页 + 分享弹窗的昵称(英文昵称)
低(7 处):分享密钥、错误文本、学区名、例句等——模式存在但数据短或含空格,暂不处理。
修复方式统一:
- 单词类(flashcard、翻译词、历史词):
min-w-0+break-all - 文本类(翻译、昵称、分组名):
min-w-0+break-words,或块级直接加break-words
经验
- flex 子项想收缩?必须
min-w-0。 没有它,break-words、truncate的兄弟overflow全是摆设,内容直接溢出被裁。 - "首字母变样"是横向裁切的典型症状。居中布局溢出时左右对称裁,别只顾着看尾巴。
- UI bug 也要全库排查。同一根因往往不止一处,
flex+ 动态文本 +overflow-hidden的组合在列表/卡片里到处都是。
版本:热更新,deploy-full.sh 部署,无需 bump。