Inline 与 inline-block · 拆解
为什么 inline-block 的 margin-bottom: -20px 反而把元素往下推; 为什么 <a> 里放一个 <img> 后高度多出几像素;为什么两个 inline-block 之间总有一条用 margin 消不掉的窄缝——这些反直觉现象背后是同一套机制: Inline Formatting Context (IFC) 里,行内框 inline box 按 vertical-align 把自己排进行框 line box,而默认的对齐线是 baseline。
一条主线讲清:先分清 line box 与 inline box 两个概念,看清行框高度由谁决定; 再讲清 baseline 与 vertical-align(尤其 inline-block 的 baseline 位置); 然后分析三道经典问题——负 margin 下移、img 撑高、input 与 label 错位(后两道同属「替换元素 baseline 落点」);随后说明 inline-block 间隙的来历,以及 inline / inline-block / block 三者行为对照 + 实战修法;另有一页工程配方——图标如何对齐文本(cap 单位 / ZWSP strut / 奇偶 1px);末页延伸到规范前沿——基线从哪一行来(baseline-source 与 SVG 的 dominant-baseline / alignment-baseline)。 每页都可拖滑块 / 切换开关,叠加层用真实 getBoundingClientRect() 把对齐线画出来。 前置知识:本系列默认 content-area / 行框「已经存在」,它们如何从字体度量算出, 可先看 font-features · 字体度量。
取材自知乎多篇经典解答:负 margin 下移(貘吃馍香)、img 撑高(Geeker)、input 与 label 错位(貘吃馍香)、 vertical-align:top 图解(貘吃馍香)、baseline 规则的历史由来(贺师俊),并以 CSS 2.1 §9.4.2 / §10.8、 MDN IFC 与 w3help RD1016 文档校准。
行框 line box vs 行内框 inline box
同一行里这两个是不同的盒子:每个 inline-level 内容是一个 inline box,它们排成的一整行是一个 line box。拖动高矮不同的 inline-block,实时看 line box 的上下边界如何被「最高顶边 / 最低底边」撑开。
baseline 与 vertical-align:对齐线在哪
行内框默认按 baseline 对齐。逐个切 top / middle / bottom / text-bottom 看 inline-block 怎么移动;再讲清关键规则——inline-block 的 baseline:有内容时是最后一行的 baseline,而空盒子或 overflow≠ visible 时改取 margin-bottom 边(负 margin / img 撑高 / input 错位三道谜题共同的前提)。
负 margin-bottom 为什么把元素「往下推」
知乎经典问题复现:三个 inline-block 并排,中间那个 margin-bottom: -20px,结果它的 border 反而下移了。叠加 baseline 对齐线 / border box / margin box 实时拆解:baseline 对齐的是下外边距边,负值把基准抬高 → border 被挤下去,而 line box 高度保持不变。另外解释 margin-top 负值为何「看似无效」。
替换元素的 baseline:img 撑高 vs input 错位
两道知乎经典问题合一页:<img> 与 <input> 都是行内替换元素、都默认 baseline 对齐,但 baseline 落点不同——img 在底边(旁边 strut 的 descent 撑出图底那条缝),input 的 baseline 则位于盒子内部(它和 inline-block <label> 的对齐实测发现:现代浏览器默认其实对得很齐,反而是改成 vertical-align:top 才错位)。叠加层把两者的 baseline 实测画出来对照,各配一键修法。
inline-block 之间的空白间隙
把几个 inline-block 分行写在 HTML 里,它们之间多出约 4px 的缝——因为源码里的换行 / 空格被折叠成一个空白字符,占了一个空格宽。切换「源码里有无空白」看缝隙出现 / 消失,并排对比四种修法:父级 font-size:0、负 margin、注释消除空白、改用 flex。
inline / inline-block / block 对照 + 修法总结
一个元素切三种 display,给它 width / height / margin / padding,实时标注哪些属性生效、哪些被忽略(inline 的垂直 padding 视觉溢出却不推开行高)。再把全系列的实战修法收成一张速查表:垂直居中、消除图底空隙、清理间隙各对应哪种方案。
图标如何对齐文本:cap 单位与 ZWSP strut
把本系列的 IFC 机理应用到一个工程任务:给图标对齐文字。难点是文字视觉重心在 cap 中线,既不是 baseline 也不是 middle 对的 x 中线。四种对齐法同台实测(叠加 baseline / x-line / cap-line),两种核心方案:translateY(calc(50% - 1cap/2)) 用 cap 单位免去 hardcode 0.7em、inline-flex + 用 ZWSP 造 strut(推荐,不依赖硬编码数值);末尾复现「用了 flex 仍差 1px」的奇偶取整问题。
基线从哪一行来:baseline-source 与 SVG 基线属性
多行 inline-block 默认拿末行 baseline 对外、inline-flex 拿首行——CSS Inline L3 的 baseline-source(auto / first / last)把这个固定的默认变成开关,实测对照。再演示「没有行可取」时的 fallback 规则:空盒 / overflow≠ visible → margin 底边缘(拖 margin-bottom 看对齐线跟着 margin 边走);最后在 SVG 中切换 dominant-baseline / alignment-baseline,看「内容相对基线怎么挂」与 vertical-align 的分工。
相关链接
- inline-block 元素设置 margin-bottom 为负值后为什么会下移? zhihu.com · 貘吃馍香 负 margin 谜题出处。从 IFC / 行框高度的角度解释负 margin-bottom 与负 margin-top 的视觉效果。
- 为什么 a 标签中使用 img 后的高度多了几个像素? zhihu.com · Geeker img 撑高谜题出处。匿名行级盒子的 line-height + baseline 对齐把 a 撑高,给出三种根治办法。
- 设为 inline-block 的标签和 input 并排放置为何会错位? zhihu.com · 貘吃馍香 input 错位谜题出处。默认 baseline 对齐,而 input 这种替换元素的 baseline 并不在元素底部 → 和 inline-block 标签高低错位。
- RD1016:替换元素与相邻内容按 baseline 对齐导致的错位 w3help.org input 错位谜题的规范级解释:行内替换元素(img / input / select 等)的 baseline 与相邻 inline 内容对齐时的兼容性陷阱与修法。
- 关于 vertical-align: top 问题? zhihu.com · 貘吃馍香 图解匿名行内框继承 line-height、leading / half-leading、混合行高下 baseline 对齐与 vertical-align:top 的排布(02 页 worked example 蓝本)。
-
图标如何对齐文本
zhuanlan.zhihu.com · 长天之云
07 页出处。从字体度量(cap-line / x-height)讲图标对齐文本:近似对齐用
cap单位偏移,精确对齐用 ZWSP 造局部 strut(inline-flex / inline-block hack),并列出 iconSize/fontSize/lineHeight 奇偶导致的 1px 误差。 - CSS 2.1 中为何规定行内块 overflow 非 visible 时基线是底部外边界? zhihu.com · 贺师俊 解释这条 baseline 规则的历史由来:inline-block 是 CSS2 后加,有滚动时定不了末行→只能取盒边(类比 iframe);首行对齐会与 CSS1 图片对齐不一致;CSS Inline L3 用 inline-box-align 重定义。
- Inline formatting context · MDN developer.mozilla.org IFC 中 line box / inline box 的排布规则、line-height 与 vertical-align 如何决定行框高度。
- CSS 2.2 §9.4.2 Inline formatting contexts w3.org IFC 的规范定义本身:line box / inline box 怎么排、vertical-align 决定矮盒的垂直对齐、行框过窄时 inline box 如何拆到多行(断点处 margin/border/padding 不显示)、以及空 line box 视为零高/不存在。整个系列的规范总出处。
- CSS 2.1 §10.8 Line height calculations w3.org 规范原文:strut、leading、inline-block 的 baseline 取值规则(空盒子 / overflow≠visible → bottom margin edge)。
-
CSS Inline Layout Module Level 3 · baseline-source
drafts.csswg.org · CSSWG
08 页主角的规范本体:在 L3 里
baseline-source(auto / first / last)与alignment-baseline、baseline-shift一起,把vertical-align重定义为这三者的 shorthand。 - baseline-source · MDN developer.mozilla.org 08 页主角:显式指定多行 inline-level 盒拿首行还是末行 baseline 对外(auto / first / last);auto 的默认即「inline-block 取末行、其余取首行」。
- Can I use · baseline-source caniuse.com baseline-source 的实时浏览器支持矩阵:Chrome/Edge 111+、Firefox 115+ 已支持,Safari 暂未实现。
- dominant-baseline · MDN developer.mozilla.org SVG 文本的「主基线」选择:alphabetic / central / hanging / middle / text-top 等。08 页 SVG 基线两小节的参照文档(同页另见 alignment-baseline)。
- vertical-align · MDN developer.mozilla.org baseline / middle / text-top / text-bottom / top / bottom 各取值的精确含义与适用对象(只作用于 inline 与 table-cell)。
- Deep dive CSS: font metrics, line-height and vertical-align iamvdo.me · Vincent De Oliveira 本系列主题的经典长文:content-area、leading 上下半分、line-height:normal、vertical-align 的常见误用,系统讲解 —— 和本系列各页正好对应。(content-area / line-height:normal 怎么从字体度量算出,见下面那条交叉链接。)
- 姊妹页:字体度量——content-area 从哪来 playground · font-features 本系列假设 content-area / 行框「已经存在」并讲它们怎么对齐;那页用 Canvas 实测把 em-square / ascender / descender → content-area、line-height:normal 的来历画出来,正好接在这之前。