替换元素的 baseline:img 撑高 vs input 错位
<img> 和 <input> 都是行内替换元素,默认都按 baseline 对齐——可它们的 baseline 不在同一个地方:<img> 的 baseline 就是它的下边,而 <input> 这类表单控件的 baseline
藏在盒子内部(由 UA 决定,不在底部)。同一条规则、两种 baseline 落点,正好酿成两个经典现象:图片底下凭空多一条缝、inline-block 的 <label> 和 <input> 并排却高低错位。本页把这两个 case 并到一起,用真实
getBoundingClientRect() 把各自的 baseline 画出来对照。本页依赖 02 · baseline 与 vertical-align 讲过的对齐规则与 strut 概念。
1 · <img>:baseline = 底边 → 撑高几像素
把图片紧紧包在链接里 <a><img></a>,你会发现 <a> 的背景 / 边框比图高出 3~5px,底下凭空垫了一条缝。<img> 的下边要坐到这一行的 baseline 上,而行里那个看不见的匿名行内框 / strut 带着
line-height,把字母「g」尾巴垂下去的空间(descent)留在了图的下方。
2 · 为什么会有这条缝
<img>默认display: inline,是行内替换元素,默认vertical-align: baseline——它的下边要坐到这一行的 baseline 上。- 这一行哪怕没有可见文字,也存在一个高度等于
line-height的 strut(匿名行内框的支柱)。它也按 baseline 对齐,但它有自己的下伸部 descent(留给 g、y、p 尾巴的空间)。 - strut 的 descent 落在 baseline 下方,于是 line box 的底边被它顶到了图的更下面;
<a>(这一行的宿主)只能跟着长高 → 图底下多出那条缝 ≈ 字体的 descent。
3 · 三种根治方案(对应上方按钮)
- **其一,消掉匿名框的高度:**给
<a>设line-height: 0或font-size: 0。strut 没了高度 → 没有 descent → 缝消失。 - **其二,改对齐方式:**给
<img>设vertical-align: top(或bottom)。不再按 baseline 对齐,自然没有「baseline 之下的 descent」这回事。 - **其三,让图离开 IFC:**给
<img>设display: block。它变成块级,根本不参与行内排布,也就没有行内框对齐问题。
注意 vertical-align: middle 不一定清零:它把图中线对到「锚字符 x 的中线」,缝可能变小却未必为 0(还可能上下都留)。要稳定消除,用上面「消匿名框高度 / vertical-align:top /
display:block」三种方案。实际项目里图标按钮、轮播图、九宫格布局最常遇到这个问题。
4 · <input> 的 baseline 在内部:老题说的「错位」今天还成立吗
另一道知乎经典问题(貘吃馍香):一个 display: inline-block 的 <label> 和一个 <input> 并排「会错位」。这页不照搬结论,而是用实测验一验——在今天的浏览器里它们到底错不错,以及 <input> 的 baseline 究竟在哪。<input>
是替换元素,它的 baseline 不在盒子底部、而在控件内部(UA 规定);<label> 则用自己末行文字的 baseline。下面 label 用大字号、input 用小字号(故意拉开,看 baseline 怎么对),切 vertical-align 看谁更齐:
结论与一个反转:<img> 的 baseline 在底边、<input> 的 baseline 在盒子内部(实测它盒底没贴 baseline)。也正因为在内部,现代浏览器里 label 和 input 按默认
baseline 对齐反而对得很齐;真把它们拉错位的,往往是改成 vertical-align: top(盒高不同就错)。原问题(2014)的「严重错位」更多是当年各浏览器对替换元素 baseline 实现不一致的产物——见 w3help · RD1016。稳妥做法是用
vertical-align: middle 或 flex。