行框 line box vs 行内框 inline box
本系列分析的所有现象都建立在这对概念上,先分清:一段 inline 内容在排版时,每个 inline-level 的东西(一截文字、一个 <img>、一个 inline-block)各自是一个 行内框 inline box;浏览器把同一行里的这些 inline box 收拢进一个
行框 line box。行框的高度,由这一行里所有行内框按 vertical-align 对齐后「最高顶边到最低底边」的距离决定——不是由某一个盒子单独决定。
**关键:**哪怕一行里只有文字,也有一个看不见的 strut(支柱)——一个高度等于 line-height 的零宽 inline box,默认就把行框撑到至少 line-height 高。这就是为什么「空的一行也有高度」。
但「彻底空」的行不算:规范(CSS 2.2 §9.4.2)的原话是——一个 line box 若既没文字、没保留的空白、也没有带非零 margin/border/padding 的 inline,就被当作零高 line box,而且「视为不存在」。换句话说:上面那个 strut
能撑起高度,前提是这行里有内容(哪怕只是一个空格);若完全为空,这行不占位。这条「有内容才存在」正是 inline-block 间隙(空格 = 内容 → 占一格)和 img 撑高(strut 的 descent)的底层依据。
1 · 动手:把行框撑高的是谁
下面一行里有一段锚文本(带 strut)和两个 inline-block 盒子。拖滑块改两个盒子的高度,看蓝色实线标出的 line box 上下边界:它永远贴着当前最高的那个,高度由最高者决定。把两个盒子都调矮于文字行高时,撑住行框的就轮到那段文字的 strut 了。
2 · 所以「行框高度」到底怎么算
- 先把这一行的每个 inline box 量出来:文字用它的
line-height,替换元素 /inline-block用它的外边距框 margin box 高度。 - 按各自的
vertical-align把它们在垂直方向对齐(默认baseline,详见 02 · baseline 与 vertical-align)。 - 对齐之后,取所有框里最高的顶边和最低的底边,两者的距离 = 这个 line box 的高度。
- 多行内容就是一摞 line box,行框之间从不重叠——这条性质是负 margin 谜题的最后一块拼图。
注意区分:line-height 设在文字那个 inline box 上;而一个高 200px 的 inline-block 不管 line-height 多少,都会用它整个 margin box 去撑行框。line box 是「容器行」,inline box
是行里的成员——两者不是同一个东西。
3 · 补两个概念:匿名行内框 与 leading
本系列其余页面会反复用到,这里先说明:
-
匿名行内框 anonymous inline box:直接写在容器里、没被任何标签包住的裸文字,也会被自动装进一个(匿名的)行内框。像
<div>one two <span>x</span> 三 四</div>会被切成三段行内框:匿名「one two」+ 具名span+ 匿名「三 四」。匿名框没法直接写样式,它的font-size/line-height等从父容器继承——所以「明明没给文字设行高,它却有高度」就是继承来的。 -
leading / half-leading(行距 / 半行距):当
line-height > font-size时,多出来的那部分叫 leading;它被平均分成两半,一半加在文字上方、一半加在下方(half-leading)。所以文字总是垂直居中在自己那个行内框里——这也是为什么纯文字行的高度正好是line-height,而文字像是浮在行中间。
把这两条接上前文:一行里既有继承了 line-height 的匿名文字框,又有显式设了大 line-height 或大高度的具名框 / inline-block 时,谁高谁定行框高度,其余的按 vertical-align 在里面确定自己的位置。02 · baseline 与 vertical-align
会用一个混合行高的例子(vertical-align: top)把这套规则连成一张图。