固定高度容器与动态字号直接冲突
别名: 固定行高容器 · 死高度 · intrinsic height
概念解释
一张卡片写死高度 72,里面按 16 像素、两行正文来裁。用户把字号抬到大约一倍半,两行变成约 48 的字面加行间,盒子还是 72,算术已经不够。固定高度和会变的字号同时成立时,不是谁礼貌让一下的问题,是两个约束在抢同一段像素,必有一个破。破的几乎总是字:被夹扁、被切、被缩小回去。
重排描述字该往哪走;固定高度描述盒子事先拒绝让路。冲突发生在盒子这一层,即使折行规则是对的,高度钉死也会把折行的结果切掉。
机制
界面里的高度钉来自几种看起来很正当的动机:列表要齐、骨架屏要先占位、设计稿上的栅格是 8 的倍数、图片和文字要在同一张卡里「视觉对齐」。这些动机在字号不变时成立。字号一变成变量,高度就不再是中立的版面数,它变成对行数的暗含上限:72 像素大约只请得起两行 16 像素加行间。上限是按设计者的默认档算的,用户的档不在方程里。
冲突的形式很具体。height 比 min-height 更硬:前者拒绝生长,后者只保证地板。line-clamp 配固定像素的 max-height 是双重钉。表格行高、底部栏、悬浮按钮的圆形直径,全都按某一档字算过,换档之后不是字溢出,就是控件自己被撑破。两端同时钉死——宽度已窄、高度又死——字没有任何维度可逃。
「视觉上齐」在动态字号下会变成假齐:左边那张卡的字还是两行,右边用户已经三行,硬齐高度就是切第三行。真正还能齐的,是卡片之间的间距和圆角,不是内容区的像素高。
边界
分隔线、色块、进度条这些不含字的条,高度本来就该钉。图标按钮若文字不在圆里而在旁边,圆形直径可以钉,旁边的标签要能长。媒体(图片、视频、地图)有自身的纵横比,高度可以按比例钉,叠在上面的标题则不能共享这个钉。启动闪屏、启动广告的固定画幅是内容本身,不是排版容器。列表若用固定行高做虚拟滚动,不改掉估算模型就无法尊重字号——这是虚拟化实现和动态字体的冲突,不是允许切字的理由。
怎么落地
- 含文字的容器用
min-height或内容固有高度,不用写死的height。需要齐的是间距,不是每张卡的像素高。 - 行数限制若还要,用「最多 N 行」且 N 随字号重新计算,不要用像素
max-height去假装行数。 - 底部栏、芯片、标签行改成能随文字变高,或把文字挪出被钉死的那一块。
- 打开系统更大字号,找所有高度数字和内容对不上的盒子:内部出现滚动条、半截字、字被压扁。每一处都是高度钉和字号变量还在同一方程里。