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.2
number
指不带单位的数值。它的计算值是line-height
乘当前元素的font-size
假设我现在指定
font-size: 20px; line-height: 1.2;
,line-height
最后实际值为20px * 1.2 = 24px
length
就是直接指定带单位的值,如px
,em
percentage
就是指百分比。它的计算值是百分比乘当前元素的font-size
inherit
因为浏览器实现方式差异较大,故不推荐使用
然后我就在想, 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
变成了块盒自然就没有基线对齐这些事了。