有人问我,“line-height到底是怎么一回事?”,“元素高度到底是怎么计算出来的?”。我说不出个所以然……

故有此文

首先有一点我们需要明白的是:在标准的盒模型中,height属性定义的是盒子中内容的高度。而line-height属性只能作用在行级的非替换元素上(什么是非替换元素),指定了元素形成的line box的最小高度。

常见的例子就是大段的文本了,当你对一个段落设置了固定的高度时,要么内容不多底部出现了空白,要么内容太多溢出了容器,这也是显而易见的。但是在这种情况下,是无法直接影响到文本的排版。

一个没有设置高度的段落,当包含文字的时候,它会自动获得一个恰好可以包裹着文本内容的高度。其本质是文本形成的line box具有高度而将段落撑开。此时,line box的潜在的高度的决定因素就是line-height

那么到底line-height是如何工作的呢?

先来看看W3C官方给出的解释:

The height of a line box is determined as follows:

  • The height of each inline-level box in the line box is calculated. For replaced elements, inline-block elements, and inline-table elements, this is the height of their margin box; for inline boxes, this is their ‘line-height’. (See “Calculating heights and margins” and the height of inline boxes in “Leading and half-leading”.)
  • The inline-level boxes are aligned vertically according to their ‘vertical-align’ property. In case they are aligned ‘top’ or ‘bottom’, they must be aligned so as to minimize the line box height. If such boxes are tall enough, there are multiple solutions and CSS 2.1 does not define the position of the line box’s baseline (i.e., the position of the strut, see below).
  • The line box height is the distance between the uppermost box top and the lowermost box bottom. (This includes the strut, as explained under ‘line-height’ below.)

大致的意思是,一个line box的高度有下面列举的情况来决定:

  • 对于可替换元素,inline-block元素和inline-table元素,高度又它们的外边距盒子的高度来决定;而对于inline盒子来说,高度由line-height决定
  • 行级盒子使用vertical-align属性来对齐时,如果是顶部或者底部对齐,line box的高度会达到它的最小值。如果盒子的高度足够高,则存在多种情况,同时在CSS2.1中并没有定义line box基线的位置
  • line box 的高度是最顶部的盒子顶部到最底下的盒子的底部

CSS假定每一种字体的字体规格,指定了一个在基线上方的高度和基线下方的depth(也就是两个值)。通俗的来说,就是字体占据高度,基线从所占据的高度穿过。假设用A代表基线上方的高度(指定大小的具体字体),D代表基线下方的depth,同时AD = A + D代表从上到下的距离。

在非替代元素中,用户代理一定会将所有的图像字符基于他们的基线对齐。对于每一个文字形成的字符图形来说,决定了A和D。这里所说的字符图形(glyph)是一个单独的元素可能由不同的字体组成,他们的A和D不一定相同。如果一个行级盒子没有任何的字符图形(glyph),我们认为它将包含一个strut(一个宽度为零,高度为AD的不可见的glyph)。

每一个字符图形都定义了一个leading L,其中 L = 'line-height' - AD。leading的一半添加到A的上面,另一半添加到D的下面。所以最终呢,在基线之上A' = A + L/2,在基线之下D' = D + L/2。说的直白一点,就是字体本身占据高地,当添加了line-height属性之后,L不能为负数。

inline 盒子的高度将所有的字符图形和它们上下的 hadf-leading 包裹在一起,这个高度就是我们说的“行高”(这一行的高度,不等同于line-height的值)。盒子的子元素不受这个高度的影响,

尽管margin,padding和border不会纳入inline box的高度的计算中,但是它们依旧会在盒子周围渲染。这意味这,如果指点高度的line-height的值比盒子的内容的高度小,那么padding和border的背景和颜色会流入到邻接的line box中。因为渲染顺序的关系,导致后面的line box 的boderh会覆盖前面line box的border和文本。

line-height的值

说了这么多,现在来看看line-height的使用

line-height呢有这么几个值

  • normal:告诉用户代理,在元素字体的基础上,将used value设置为一个“合理的值”,这个值和’<\number>’,有相同的意义。我们建议将normal的used value设置在1.0至1.2.
  • length:指定一个数值用于计算line box的高度,不能为负值
  • number:属性的used value是值与字体大小的乘积,不能为负值
  • percentage:属性的computed value是当前元素字体计算值的百分比,同样也不能使用负值

当一个元素中的文本包含不止一种字体时,用户代理可能会根据最大的字体大小来设置line-height的normal值。

Specified, computed, and actual values的简单解释

当用户代理解析一个文档,创建出一个DOM树时,针对当前的媒体设备,为每一个元素的每一个属性指定一个属性值。

元素属性最终的值取决于一个“四步计算”的结果:

  1. 浏览器对元素设置的默认样式(‘specified value’)
  2. 使用继承自祖先元素的值(‘computed value’)
  3. 如果有必要,转换成一个绝对的值(‘used value’)
  4. 最后根据当时的环境转换属性值(‘actual value’)

参考:
W3C line-height
W3C Assigning property values