CSS 基线与 vertical-align

CSS 行内格式化上下文里的基线、line-height、vertical-align 与常见对齐问题的系统梳理。

#tech / dev / frontend #resource / css #type / concept #status / growing

[!info] related notes

CSS 基线与 vertical-align

一句话定义

基线是行内排版里“文字站住的那条参考线”,而 vertical-align 控制的是行内盒在同一行里相对这条线如何对齐。

为什么这个点总让人混乱

因为很多人看到的是“元素没对齐”,但浏览器实际在做的是:

  • 先建立行盒 line box
  • 再根据字体度量、行高、内联盒类型计算基线
  • 最后按 vertical-align 把每个行内盒摆进这一行

所以按钮、文字、图片、inline-block 看起来没在一条线上,往往不是 Flex 失效,而是行内格式化上下文里的基线规则在起作用。

1. 基线到底是什么

可以先把一行文本想成几条看不见的参考线:

  • 顶线:字符可能接近的上边界
  • 中线:有些对齐值会参考
  • 基线:大多数字符“踩着”的线
  • 下延线:gp 这类字母往下伸出去的区域

对于普通文本,基线最常跟字体度量有关,而不是元素内容框的几何中心。

2. 哪些元素会受基线影响

最典型的是这些:

  • 纯文本节点
  • span 这类行内元素
  • inline-block
  • inline-table
  • 替换元素,如 imginput

块级元素单独占一行时,通常不直接参与这一层基线对齐。

3. 行内排版时浏览器在算什么

3.1 行盒 line box

同一行里的所有行内内容会被放进一个行盒。这个行盒的高度,通常受以下因素共同影响:

  • 字体大小
  • line-height
  • 行内盒本身的高度
  • 是否有图片、按钮、inline-block

3.2 文本的基线

普通文字的基线来自字体度量。不同字体、不同字号、不同字重,基线看起来都可能略有差异。

这就是为什么“换了一个特殊字体后突然不对齐”很常见。

3.3 inline-block 的基线

inline-block 的基线不是“盒子垂直中心”。

更接近的理解是:

  • 如果它内部有正常行内内容,基线常取最后一行行盒的基线
  • 如果没有可参与的行内内容,浏览器会退化到盒子的底边附近来处理

所以两个高度不同的 inline-block,即使都在同一行,也常常视觉上不在中线。

3.4 图片和表单控件

imginputbutton 这些替换元素或带默认样式的元素,经常有自己的对齐规则、内边距和默认 line-height,所以最容易把整行的视觉中心拉偏。

4. vertical-align 真正在控制什么

vertical-align 只对以下场景生效:

  • 行内级元素
  • 表格单元格

它不是通用的“垂直居中大法”,也不会替代 Flex/Grid 对齐。

常见取值可以这样记:

  • baseline:按基线对齐,默认值
  • middle:元素中线对齐到父行盒基线附近的中线参考,不等于几何绝对居中
  • top / bottom:对齐到当前行盒顶部或底部
  • text-top / text-bottom:更贴近文本字体盒

最常见误区是把 middle 理解成“和旁边元素完全垂直居中”。它只是在行内排版语义里尽量居中,不保证视觉绝对一致。

5. 为什么按钮、文字、图标经常错位

5.1 字体度量不同

同样是 font-size: 16px,不同字体的 x-height、ascender、descender 并不一样,基线自然会偏。

5.2 默认 line-heightpadding

按钮、输入框常带默认上下内边距和默认行高,而旁边的文字可能只是普通 span

结果就是:

  • 盒子高度不同
  • 文字落点不同
  • 基线也不同

5.3 inlineinline-block、替换元素混排

这几种盒子的基线规则不完全一样,放在一行里时很容易出现“代码看着都在一行,视觉却不平”的情况。

5.4 缩放和小数像素

浏览器缩放后,字体渲染和像素取整可能产生细微偏移,所以有时 100% 看起来正常,125% 就开始怪。

6. 放到 Flex 里为什么还会出问题

很多人以为:

display: flex;
align-items: center;

就一定彻底解决了。

align-items: center 居中的是 flex 项的盒子,不是里面文本的字体度量。

如果子项本身还是按钮、图标、文本混排,内部的:

  • line-height
  • 字体
  • padding
  • 默认样式

仍然会影响最终视觉中心。

所以常见修正方式是:

  • 把按钮本身改成 inline-flexflex
  • 统一 font-sizeline-height
  • 减少依赖默认按钮样式
  • gap 代替相邻元素 margin

7. 实战里怎么排查

建议按这个顺序看:

  1. 看相关元素的 font-size 是否一致
  2. line-height 是否一致
  3. 看按钮/输入框是否带默认 paddingborderappearance
  4. 看元素是 inlineinline-block 还是 flex
  5. 缩放页面,看是否有小数像素导致的视觉偏移
  6. 在 DevTools 里临时把按钮改成 inline-flex,观察问题是否立刻消失

8. 更稳的解决策略

方案一:统一文本系统

.label,
.button {
  font-size: 14px;
  line-height: 1.2;
}

适合纯文本差异导致的错位。

方案二:按钮内部自己做居中

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

适合按钮和旁边普通文本、图标一起出现的情况。

方案三:必要时显式指定 vertical-align

img,
.icon {
  vertical-align: middle;
}

适合图标和文字同行时的细调。

方案四:如果本质是布局问题,就不要继续纠结基线

如果你真正需要的是一组盒子整体居中,优先选:

  • Flex
  • Grid

不要强行在复杂布局里只靠 vertical-align 硬撑。

9. 面试或笔试怎么答更稳

可以直接这样答:

基线问题本质上是行内排版规则导致的。文字、按钮、图片、inline-block 的基线计算方式不完全一样,再叠加默认 line-heightpadding 和字体度量差异,就会出现看起来不在一条线上的情况。排查时我会先统一字体和行高,再看元素的显示类型;如果是按钮或图标混排,通常会改成 inline-flex 或显式加 vertical-align,而不是只盯着某一个像素去微调。

10. 最短记忆方式

  • 基线是文字排版参考线,不是盒子中心线
  • vertical-align 管的是行内对齐,不是万能垂直居中
  • Flex 居中的是盒子,内部文字是否“看起来居中”还要看字体和行高
创建于 2026/3/29 更新于 2026/5/27