line-height随字体变化而变高或变矮,根本原因是浏览器依据字体内部度量(ascent/descent/em-box)计算行框高度,而不同字体的这些度量值差异显著;例如思源黑体与Roboto在相同font-size和line-height下实际像素高度不同,Web Font加载切换时亦会引发跳变。

line-height 为什么随字体变化而变高或变矮
根本不是你设错了 line-height,而是浏览器拿不同字体的内部度量(ascent/descent/em-box)去算行框高度,而这些值在每款字体里都不一样。比如 “思源黑体” 和 “Roboto” 同样是 font-size: 16px + line-height: 1.5,实际行高可能分别是 24px 和 22px。
关键点在于:line-height 的数值(如 1.5)只是乘数,真正被乘的“基础高度”,由当前字体的度量决定——不是字号,也不是你肉眼看到的文字高度。
- 中文字体通常 ascent 较高、descent 较浅,em-box 更“方正”,行框偏高
- 西文字体(尤其窄体/几何体)常有更大 descent(为 “g”、“y” 留空间),但 ascent 可能偏低,整体行框反而更“松”
- Web Font 加载后切换字体,
line-height值没变,但实际像素高度跳变,就是这个原因
font-family 切换时 line-height 突然跳变怎么稳住
后备字体(fallback font)和主字体的度量差异,会让 line-height 在字体加载前后“抖动”。这不是渲染 bug,是字体本身设计使然。
最有效做法不是锁死字体栈,而是减少对字体度量的依赖:
立即学习“前端免费学习笔记(深入)”;
- 用
font-display: swap避免空白期,但别指望它解决跳变——swap 只管显示时机,不管度量一致性 - 所有文本容器统一设
box-sizing: border-box+ 固定height(比如height: 40px),再靠padding控制文字上下留白,绕过line-height计算 - 若必须用
line-height,优先用无单位值(line-height: 1.4),避免line-height: 24px或line-height: 1.4em—— 后者会因父级字号放大误差
input/button 里 line-height 为啥不起作用
input[type="text"] 和 button 是替换元素(replaced element),它们的垂直居中逻辑不走 line-height,而是靠 height + font-size + padding 组合撑开。
常见错误:
- 给
input设line-height: 20px,但在 Safari 中可能完全无效,甚至导致基线错位 - 用
line-height: 0+padding想“清空行高”,某些 Android WebView 会直接忽略line-height: 0,反而撑高
正确做法:显式设 height(如 height: 36px),再用 padding-top / padding-bottom 微调文字位置;vertical-align 对这类元素也无效,别白费力气。
vertical-align 怎么悄悄拉高整行高度
vertical-align 不作用于块级元素,但它会影响整行的基线位置——只要有一个 img 或 inline-block 元素没设对齐方式,默认 vertical-align: baseline,就会为 descender 留空隙,把整行行框往上顶。
典型现象:
- 一个
<img>放在文字行里,父容器高度多出 2–3px - 多个
inline-block卡片混排,有的有文字、有的只有图标,高度参差不齐
解决很简单:所有 img、input、button、span.icon 显式加 vertical-align: middle 或 vertical-align: top;不要用 vertical-align: text-bottom 这类语义模糊的值,它依赖字体 descender,反而加剧不一致。
真正难处理的,是那些你没意识到在参与行高计算的东西:一个没设 vertical-align 的图标、一段没约束 box-sizing 的 padding、甚至 Web Font 加载完成那一刻的微小重排——它们叠加起来,才让“明明写了同样的 line-height”变成一句失效的承诺。


















