本节内容非常复杂,是对上一节内容的补充和扩展,上一节中,我们知道,行盒的垂直排列使用 vertical-align 来指定,但是上一节中基本介绍的是和应用挂钩的内容,都是说怎么用,避开了很多涉及到原理性的内容,因为原理性的内容过于复杂和深入,所以这里单独介绍,学习了这个之后,前面很多关于字体的 CSS 属性都可以有一个更为清晰的认识。
当然,如果读者对这里不感兴趣,也可以直接跳过
首先,先了解什么是字体,一套字体中的每一个文字本质上其实都是一个图像,我们要制作一套字体,其实是会制作很多个文字,为了保证这些文字是对其的,我们需要一些参考线,文字有五根参考线,从上到下分别是顶线、上基线、基线、下基线、底线。这五个线就跟田字格一样,主要起到一个文字对其,以及限定尺寸的作用。所有的字体都有这五根参考线,但每两条参考线之间的间隔距离,不同的字体可以不一样。
顶线和底线的距离就是这套字体的实际大小,这个实际大小其实是没有单位的,例如这套字体的实际大小为 y。一套字体也有一个相对大小,例如相对大小为 x,那么当我把字体大小设置为 20 px 的时候,实际大小为 20*(y/x) 像素,看懂了吗,也就是相对大小就是单位 1,比如相对大小为 1000,实际大小为 800,这个意思就是,当我将字体大小设置为 1000 的时候,这个字体的实际大小就是 800。
以 consolas 字体为例,这套字体的相对大小为 2048,实际大小为 2398,这就意味着,将这套字体的字体大小设置为 2048 px 之后,其实际的字体大小应该是 2398 px,按比例换算,当字体大小设置为 100 px 的时候,实际的字体大小应该是 100*(2398/2048)≈117。我们可以尝试一下:

可以看到,上图中高亮部分,顶部就是顶线,底部就是底线。顶线到底线实际上就是撑开了盒子的 content-box 区域。由于以上种种机制,所以当我们给一个行盒设置背景的时候,文字上方和下方往往会多出来一点。
其实很多字体,其实际大小都是会超过它相对大小的。
以前我们将文字大小设置为 100 像素,但实际上盒子内容区的大小往往不是 100 像素,相信学习完了以上内容,读者应该就可以解释这个问题了。
接下来是多行文字的问题,多行文字的情况下,上下并不一定是紧贴着的,在字体设置的时候,顶线上方和底线下方就会有一个距离,这个距离称作 line-gap,一个文字上方和下方各有一个 line-gap,用于分割每一行文字。
实际上,行高就是指文字的实际大小加上两个 line-gap 的大小。当然,这个 line-gap 可以是负数,这样多行文字之间就可能出现重叠显示。
从原理上来说,line-height 设置的就是文字实际大小加上两个 line-gap 的大小,但是我们也可以将 line-height 理解为两行文字基线的距离,这从数值上是等价的。
一般情况下,我们将 line-height 设置为 normal 即可,或者说不动它。这样的话就会使用字体设计时设置的默认 line-gap。
接下来考虑一个巨恶心的属性,即 vertical-align。
首先,一个元素如果其子元素出现了行盒,那么这个元素内部其实也会产生参考线,这个参考线的位置,实际上取决于这个元素的字体和字体大小。
如果一个块盒里面直接书写文字,在 9.浮动 中我们介绍过匿名盒子的概念,当块盒内部直接放置了一个文本的情况下,会自动使用匿名行盒来包裹这个文字,这个匿名行盒也是行盒。
这个时候就出现了一个问题,如果一个元素内部出现了行盒,它内部会根据自己的字体样式和大小生成一个参考线,而行盒本身又有一个自己的参考线,这种情况下就出现了一个对其的问题,按照哪根线对其,就是行盒的 vertical-align 属性设置的,默认为 baseline,即基线对齐,即该元素的基线与父元素的基线对其。
我们也可以设置其他的值
- super: 元素的基线与父元素的上基线对齐
- sub:元素的基线与父元素的下标基线对齐
- text-top: 元素的顶部(包含 gap-line)与父元素的顶边对其
- text-bottom: 元素的底部(包含 gap-line)与父元素的底边对其
- 数值:相对于基线的偏移量,向上为正,向下为负。(如果设置为百分比,则相对于自身字体的总高度(包括 gap-line))
- top: 该元素的顶部与整行的最高顶边对其
- bottom: 该元素的底部与整行的最低底边对其
- middle: 该元素的中线(中间位置)和父元素的 X 字母高度一半的位置对其。
行盒组合起来可以形成多行,每一行的区域叫做
line-box,可翻译为行框,每一行都有一个行框,行框的顶边是这一行的最高顶边,底边是这一行最低的底边。实际上,一个元素占用的实际高度就按照 line-box 计算。
注:行盒的英文为inline-box,并不是line-box
line-box 是承载文字的必要条件,也就是说只要有文字,就一定会生成 line-box,只有以下情况才不会生成行框
- 元素内部没有任何行盒
- 字体大小为 0
如果理解了第二点,将父元素的字体大小设置为 0,那么这个父元素不生成行框,那么此时该元素内部不可能显示任何文字。
可替换元素虽然也有基线,但和行盒不一样
- 图片:基线位于 margin-box 的底部
- 表单元素:基线位于内容的底边
实际上,正是由于图片的基线位于 margin-box 的底部,而元素默认是基线对齐,所以图片的 margin-box 的底部就会和父元素的基线对齐,而父元素的基线距离底线又有一定的距离,所以就会产生上一节中图片底部白边的问题。
对于行块盒而言,其最后一行会有 line-box,行块盒会以最后一行的基线作为整个行块盒的基线。而如果行块盒内部没有行盒,那么会使用 margin-box 的底部作为基线。