line-height 是为数不多支持数值可以带单位可以不带单位的属性,但是其效果确实千差万别,今天会用数据来侃一侃其中的差异性。前面讲 IFC的时候说过要好好聊一聊行盒的高度,就在本文中来个大揭秘吧。
前方高能提示,第一大节全部都是原理性的研究,不想看可以略过-_-但你会后悔的,后面是实用性比较强的知识。
定义二三事
行高只能算是 line-height 的中文翻译, CSS 规范 只对 line-height 作出一个稍显模糊的定义。
line-height值(即行高)就是两行(属性一样的)文本的基线的距离
两个不同字体或者不同大小的文字,它们的基线位置各不相同,基线距离根本就不能得出 line-height 值,这也是为什么我要强调属性一样的文字。
基线解释
这里又要懵逼了,什么叫做基线?我怎么知道它在哪里?
我们小学都用过英语四线三格纸,召唤一下它,唤醒我们内涵无限的童年。相信大家一看就知道这四条线分别代表哪个部分了。

line-height 高度机制
谁 ‘撑开’ 高度
当我们给一个空的 div 添加任意文字时, div 的高度会从 0 变成某一个值,那 div 是由文字 ‘撑开’ 的吗?不,是line-height的作用。
看一下我对下面两个 div 设置的 style :
|
|
第一个 div 虽然字很大,但是由于 line-height 为 0 ,最后落得一个高度为 0 的结果;第二个 div 虽然 font-size 为 0 字儿都显示不出来了,但是愣是让 div 高度变为了 40px 。
所以, line-height ‘撑开’ 了匿名内联盒的高度,继而 ‘撑开’ 了 div 。如果我们平时开发,遇到想设置文字垂直居中,而设置 line-height = height 时,可以把 height 去掉了,因为 line-height 完全可以替代 height 的作用。
line-height 如何 ‘撑开’
我们说是 line-height ‘撑开’ 了内联盒,其实不够准确。确实与 line-height 有关,但是它更像是一个指挥关,它后面还有一套时刻运转的机制来提供服务。

这里我想强调的是,基线之间的距离只是作为 line-height 的值,不代表 line-height 是这块区域的, line-height 是没有区域之说的,它就是一个值,一个概念。
内联盒真实的区域划分就是如上图所示,内联盒真正的组成就是由内容区域以及上下半行距组成。
顶线与底线之间的区域我们叫做内容区域,内容区域只与字体及字号相关,这个知道就行。上一行文本底线与下一行文本顶线之间的距离叫做行距,这个行距应当分成两半,上一行文本的下半行距,以及下一行文本的上半行距,我在图中在它们中间留了一条缝隙以示区分。
上半行距 + 内容区域 + 下半行距 = line-height
浏览器会根据字形来确定内容区域的高度 h,然后根据 (line-height - h) / 2 来计算出上半行距和下半行距。
如果我们定义了一行文本 line-height 为 30px ,假设内容区域高度为 16px ,那 上半距 = 下半距 = (30px - 16px) / 2 = 7px 。
其实,到了现在我们可以理解,为什么我们给单行文本设置了 line-height 之后,文本会垂直居中。但是,文本其实没有真正的垂直居中。因为真正垂直居中的是内容区域,而文字在内容区域中并不是垂直居中,通过上面的图就可以发现。但这一点不需要过度计较,因为这个平时压根看不出来。
行盒的高度
我们平时可能听的比较多的版本是,行盒高度是由这一行中最大的 line-height 决定的,这句话其实是错的,因为它完全忽略了 vertical-align 存在的情况。
IFC 一问中已经讲到,行盒由一行内联级盒组成,行盒的高度就是最高的盒(上半边距)顶部到最低的盒(下半边距)底部的距离。

line-height各属性值
来回顾一下 line-height 可设置的属性值类型:
Value: normal | < number > | < length > | < percentage > | inherit
Tips:不可以对 line-height 设置负值!
normal没什么太多可讲的,这是line-height的默认值。它实际表现等同于1.1 ~ 1.2number指不带单位的数值。它的计算值是line-height乘当前元素的font-size假设我现在指定
font-size: 20px; line-height: 1.2;,line-height最后实际值为20px * 1.2 = 24pxlength就是直接指定带单位的值,如px,empercentage就是指百分比。它的计算值是百分比乘当前元素的font-sizeinherit因为浏览器实现方式差异较大,故不推荐使用
然后我就在想, line-height: 1.2 和 line-height: 120% 最后计算值都是一样,那为什么要设置两种方式呢?存在必有原因。
最重要的一点:line-height: 1.2 继承给子元素的是 line-height: 1.2 ,而 line-height: 120% 是先将 line-height 计算出来,再将此计算值继承给子元素。
line-height 为 0
line-height 为 0 ,公式 上半行距 + 内容区域 + 下半行距 = line-height 依然成立,设内容区域高度为 h ,此时上下半距都为 -h/2 。但是文本在页面中是不会占据任何空间的。
图片底边距
这里说个题外话。。。 line-height 对 img 是不起作用的,但是对同样是可替换元素的 input 却能起到作用,这是为什么呢?后来我想了想,是有原因的,因为 line-height 只能对文本起作用, input 里面是有可以文本的,而 img 中却不可以,同样 object 也是一样。
瞪大双眼看一看,图片底边与 div 底边并没有完全贴合,还有一个很小的间隙,这个其实是 line-height 与 vertical-align 共同作用带来的影响。
原因探析
img 默认是 baseline 对齐,看一下图示。

红色的线是基线,绿色的线是底线,底线距离 div 底边还有很小的一点距离,就是下半边距。
我们的文字产生的匿名内联盒自然也是有高度的,基线以下的部分也得显示出来,所以图片下方边距,正是 文本基线到底线的距离 + 下半边距 。div 的高度就是它所产生的包含块的高度,就是行盒的高度总和(此例中只有一行,所以等于该行盒高),就是 图片高度 + 文本基线到底线的距离 + 下半边距 。
html5 带来的变化
在 html4 中,如果没有文字则自然没有上面所说的图片底边距问题,但是情况在 html5 有了变化。
即使没有文本,图片也会当做它身边有文本存在,此时它会带来两种与 html4 不一样的表现。
- 永远存在图片底边距问题
- 如果图片高度低于文本高度,
div高度依旧等于文本高度
解决方法
div设置line-height: 0或者font-size: 0
文本不占据空间,自然不会凸出来了。但是这个方法显然没有那么美妙,万一我有文字需要添加呢,是吧img设置vertical-align: bottom
让图片与行盒底部对齐,这样子文字就不会有一部分凸出来了。img设置display: block或者float: left
变成了块盒自然就没有基线对齐这些事了。