深入理解CSS,css中补充的line

深入理解CSS:font metrics, line-height 以及 vertical-align

2017/04/28 · CSS · 2 评论 · font metrics, line-height, vertical-align

原文出处: Vincent De Oliveira   译文出处:众成翻译   

Line-heightvertical-align 是比较简单的CSS属性,以至于我们大多数人都觉得完全理解这两个属性是如何工作以及如何使用它们。实际并非如此。这两个属性非常复杂,也许可以说是最难理解的属性了。CSS有一个鲜为人知的特性:内联元素格式化。这两者恰好在这个特性上起着重要作用。

例如line-height 可以是一个长度或者是一个没有单位的数值注1,但它的默认值是normalnormal又代表什么呢?我们把它当作是1或者是1.2,甚至连CSS spec都没有讲清楚这个值是什么。我们知道,无单位的line-heightfont-size相关联的,但问题是font-size:100px在不同字体时表现是不一样的,那line-height是相同还是不同的? 它的值真的在1到1.2之间吗? 还有 vertical-align,它对line-height有什么影响?

因此我们需要深入研究一下这个不那么简单的CSS机制。

1,行高的定义

行高指的是文本行的基线间的距离,但是文本之间的空白距离不仅仅是行高决定的, 同时也受字号的影响

声明本文转自:

line-height属性的具体定义列表如下:
语法: line-height : normal | <实数> | <长度> | <百分比> | inherit
说明: 设置元素中行的高度。
值: normal:默认行高,一般为1到1.2; 实数:实数值,缩放因子; 长度:合法的长度值,可为负数; 百分比:百分比取值基于元素的字体尺寸。
初始值: normal
继承性: 继承
适用于: 所有元素
媒体: 视觉
计算值: 长度和百分比值为绝对值;其他同指定值。
行高指的是文本行的基线间的距离。而基线(Base line),指的是一行字横排时下沿的基础线,基线并不是汉字的下端沿,而是英文字母x的下 端沿,同时还有文字的顶线(Top line)、中线(Middle line)和底线(Bottom line),用以确定文字行的位置,如图7-17 所示。
图片 1
图7-17 文字的基线
行高与字体尺寸的差称为行距(leading),如图7-18所示。
图片 2
图7-18 行高与行距
7.3.2 内容区域、行内框和行框
理论上讲,一行中的每个元素都有一个内容区域,它是由字体尺寸决定的,如图7-19所示。
图片 3
图7-19 内容区域
行内元素会生成一个行内框(inline box),行内框只是一个概念,它无法显示出来,但是它又确实存在。在没有其他因素影响的时候,行内框等于内容区域,而设定行高则可以增加或者减少行内框的高度,即:将行距的值(行高-字体尺寸)除以2,分别增加到内容区域的上下两边,如图7-20所示。
图片 4
图7-20 行内框与行高
由于行高可以应用在任何元素上,因此同一行内的若干元素可能有不同的行高和行内框高,例如有如下代码,其显示如图7-21所示。
    <p style=”line-height:20px;”>行高20px。<strong style=”line-height:50px;”> 行高50px。</strong><span style=”line-height:30px;”>行高30px。</span></p>
图片 5
图7-21 行内框与行框
这里又有一个新的概念——行框(line box)。同行内框类似,行框是指本行的一个虚拟的矩形框,其高度等于本行内所有元素中行高最大的值。因此,当有多行内容时,每行都会有自己的行框,如图7-22所示。
图片 6
图7-22 多行内容的行框
提示:理解行框和行内框的概念对于学习本章[7.4垂直对齐:vertical-align属性]一节的内容非常重要。
注意:行框的高度只同本行内元素的行高有关,而和父元素的高度(height)无关。
7.3.3 行高的计算与继承
以em、ex和百分比为单位的行高,其基数是元素本身的字体尺寸。例如有代码如下:
    <p style=”font-size:20px;line-height:2em;”>字高20px,行高2em。</p> <p style=”font-size:30px;line-height:2em;”>字高30px,行高2em。</p>
2个段落的行高都为2em,但是字体大小不同,因此显示如图7-23所示。
图片 7
图7-23 行高的计算
行高可以设定得比字体高度小,此时多行的文字将叠加到一起,例如有如下代码,其显示如图7-24所示。
    p { font-size : 20px; line-height :10px; }
    <p>字高20px,行高10px。此时多行的文字将叠加到一起。</p>
图片 8
图7-24 比字体高度小的行高
行高是可继承的,但是继承的是计算值,例如有如下代码:
    p { font-size :20px; line-height : 2em; }
    p span { font-size : 30px; }
    <p>字高20px。<span>字高30px。</span></p>
<p>元素的行高2em,字体尺寸为20px,因此计算值为40px,虽然<span>元素本身的字体尺寸为30px,不过其继承的行高仍为40px。但是在不同的浏览器内显示的效果却不尽相同,如图7-25所示。
图片 9
图7-25 行高的不同表现
由于继承的是计算值,因此当元素内的文字字体尺寸不一样的时候,如果设定固定的行高很可能造成字体的重叠,例如有如下代码,其显示如图7-26所示。
    p { font-size : 20px; line-height : 1em; }
    p span { font-size : 30px; }
    <p>字高20px,行高1em,当文本为多行时可能会发生文字重叠的现象。<span>字高30px。</span></p>
图片 10
图7-26行高继承造成文字叠加
为了避免这种情况,可以为每个元素单独定义行高,但是这样很烦琐,因此可以定义一个没有单位的实数值作为缩放因子来统一控制行高,缩放因子是直接继承的,而不是继承计算值。例如修改上例中的行高为:
    p { line-height : 1; }
则上例中的XHTML代码显示如图7-27所示。
图片 11
图7-27缩放因子对行高的影响
当内容中含有图片的时候,如果图片的高度大于行高,则含有图片行的行框将被撑开到图片的高度,如图7-28所示。
图片 12
图7-28 含有图片的行
注意:图片虽然撑开了行框,但是不会影响行高,因此也不会影响到基于行高来计算的其他属性。
提示:当行内含有图片的时候,图片和文字的垂直对齐方式默认是基线对齐,关于垂直对齐将在本章[7.4 垂直对齐:vertical-align属性]一节中讨论。
7.3.4 浏览器的差别与错误
浏览器在显示的时候往往会有自己的表现形式,例如在Opera内,行高将按照CSS定义的将行距除以2增加到内容区域的上下两边,而IE和Firefox则不是完全平分,如图7-29所示。
图片 13
图7-29 不同浏览器对行高的显示
不过,相差的1至2个像素在实际显示中一般不会有太大的影响,因此可以忽略不计。比较严重的错误是IE 6.0对于含有图片或者表单元等可替换行内元素的行高失效的问题,不过,在IE 7.0中已经修正了这个错误,但是其表现同其它浏览器也不相同。例如有如下代码,其显示如图7-30所示。
    #lineHeight4 p { line-height : 60px; }
    #lineHeight4 fieldset{ border : 0; }
    <div id=”lineHeight4″> <p>内容含有图片在[IE 6]内浏览line-height将失效。<img src=”../../img/ddcat_anim.gif” alt=”图片” width=”88″ height=”31″ /></p> <form id=”testForm” action=”#”> <fieldset> <p><label for=”test1″>表单元素</label>< input type=”text” maxlength=”16″ value=”IE6内行高失效” /></p> </fieldset> </form> </div>
图片 14
图7-30 包含替换元素的行高在IE内失效
由图7-30读者可以发现,IE 7.0中,将半行距分别加在了图片的上下,而由于图片默认是基线对齐,因此文字的基线下移了,这显然不符合CSS中的规定。
对于IE 6.0中行高失效的问题,需要使用CSS Hack手段来针对IE 6.0设定替换元素的上下补白来修正。
提示:关于针对IE 6的CSS Hack,请参见本书[第16章:浏览器与Hack]。
7.3.5 应用:单行文字在垂直方向居中
在网页设计中,往往为了突出标题而添加背景图案,如图7-31所示。
图片 15
图7-31 包含背景图片的标题
假设此标题的XHTML代码如下:
    <div id=”#sample”> <h2>热门帖大盘点</h2> …… </div>
此时如果只设定<h2>的背景图片和高,则文字会偏上,如图7-32所示。
图片 16
图7-32 未设定行高的标题文字
针对这个现象,一般只需要设定与高度相等的行高即可,相关代码如下:
    #sample h2 { height : 31px; line-height : 31px; …… }
此时在浏览器内文字已经在垂直位置上居中显示,如图7-33所示。
图片 17
图7-33 设定行高后的标题文字
此方法同样可以运用在其他需要文字垂直居中显示的地方,例如列表项、导航条等等。
上一小节讲解了行高与单行纯文字的垂直居中,而如果行内含有图片和文字,在浏览器内浏览时,读者可以发现文字和图片在垂直方向并不是沿中线居中,而是沿基线对齐,如图7-34所示。
图片 18
图7-34 文字和图片内容默认垂直对齐方式为基线对齐
这是因为,元素默认的垂直对齐方式为基线对齐(vertical-align: baseline)。

让我们先研究下font-size

看看这段简单的HTML代码,包含3个,每个都有不同的 font-family.

XHTML

<p> <span class="a">Ba</span> <span class="b">Ba</span> <span class="c">Ba</span> </p>

1
2
3
4
5
<p>
    <span class="a">Ba</span>
    <span class="b">Ba</span>
    <span class="c">Ba</span>
</p>

CSS

p { font-size: 100px } .a { font-family: Helvetica } .b { font-family: Gruppo } .c { font-family: Catamaran }

1
2
3
4
p  { font-size: 100px }
.a { font-family: Helvetica }
.b { font-family: Gruppo    }
.c { font-family: Catamaran }

使用同样的font-size和不同的font-family会产生不同高度的元素: 图片 19

图1.不同font-family, 相同font-size, 高度不同

即便我们意识到这点,为什么font-size: 100px 不能产生相同高度的元素呢?我测试过一些字体集,并得到以下值 Helvetica: 115px, Gruppo: 97px, Catamaran: 164px。 图片 20

图2.font-size为100px的元素高度从97px到164px不等

第一眼看上去有点不可思议,但实际上这就是这样的。原因在于字体本身。它的机制是这样:

  • 一个字体定义了它的em-square(或UPM,即每个em的单位)。也就是一个容器,每个字符将被绘制在容器里。这个正方形使用相对单位,通常设置为1000单位,但也可以是1024,2048或其他任何值。
  • 根据字体的相对单位,设置字体的其他度量值(升部,降部,大写高度,x字高等等)。请注意,某些值可能会超出这个方形容器。
  • 浏览器为了适应所需的字体大小,会缩放相对单位。

以Catamaran字体为例,并在[FontForge](https://fontforge.github.io/en-US/)中打开,看一看其中的各项指标:

  • em-square是1000个单位的。
  • 升部是1100,降部是540。在一些测试后,看上去浏览器在Mac OS上的HHead Ascent/ Descent值,Windows上的Win Ascent/Descent值(这些值可能是不同的!)。 还有,Capital Height(大写高度)是680,X height(X字高)是485。

图片 21

图3: 使用FontForge看到的字体各个度量值

这意味着Catamaran在1000个单位的容器中就用了1100 540个单位,因此使用这个字体时,如果设置font-size: 100px,那么实际高度就是164px。这个计算出的高度定义了一个元素content-area内容区域,我将在本文的其余部分引用这个术语。您可以将content-area理解为background属性应用的区域注2。

We can also predict that capital letters are 68px high (680 units) and lower case letters (x-height) are 49px high (485 units). As a result, 1ex = 49px and 1em = 100px, not 164px (thankfully, em is based on font-size, not computed height) 我们还可以预测,大写字母是68px(680单位),小写字母(X字高)高49像素(485单位)。 因此,1ex = 49px和1em = 100px,而不是164px(谢天谢地,em单位是基于font-size,而不是计算后的高度)。

图片 22

图4: Catamaran字体:UPM-每单位em数-和像素值在使用font-size:100px时值相同。

再更深入之前,我再简要介绍一下这一机制。 当一个``

``元素在屏幕上呈现时,根据它的宽度定义,可以产生许多行。 每行由一个或多个内联元素(HTML标签或文本内容的匿名内联元素)组成,称为line-boxline-box的高度由其子节点的高度决定。 因此,浏览器会计算计算line-box(从其子节点的最高点到子节点的最低点)的高度,由此便有了每个内联元素的高度。 因此(在默认情况下),line-box总是能够容纳其所有子节点。

每个HTML元素实际上是一堆line-box的集合。如果你知道每个line-box的高度,你就知道一个元素的高度。

如果我们把之前的代码改成下面这样:

 

XHTML

<p> Good design will be better. <span class="a">Ba</span> <span class="b">Ba</span> <span class="c">Ba</span> We get to make a consequence. </p>

1
2
3
4
5
6
7
<p>
    Good design will be better.
    <span class="a">Ba</span>
    <span class="b">Ba</span>
    <span class="c">Ba</span>
    We get to make a consequence.
</p>

就会生成3个line-box

  • 第一行和第三行包含一个匿名的内联元素(文本内容)。
  • 第二行包含两个匿名的内联元素,以及3个``.

图片 23

图5:这个``

``段落(黑色边框)由包含内联元素(实体边框)和匿名内联元素(虚线边框)的线框(白色边框)共同组成。

我们可以很清楚地看到,第二个line-box比其他的高,因为其子节点的content-area更高,准确的说,是因为子节点使用了Catamaran字体。

问题在于line-box的创建的过程是黑盒的,也不能使用CSS来控制。即便使用:: first-line也不能让我们设定第一个行内元素的高度。

行高是指行间的距离,也就是基线之间的距离,而只有两行文字才会存在两个基线,那么为什么单行文字还具有行高?我们怀着这个疑问往下看。

7.3 line-height

行高指的是文本行的基线间的距离,但是文本之间的空白距离不仅仅是行高决定的, 同时也受字号的影响。

7.3.1 语 法

line-height属性的具体定义列表如下:

语法: line-height : normal | <实数> | <长度> | <百分比> | inherit
说明: 设置元素中行的高度。
值: normal:默认行高,一般为1到1.2; 实数:实数值,缩放因子; 长度:合法的长度值,可为负数; 百分比:百分比取值基于元素的字体尺寸。
初始值: normal
继承性: 继承
适用于: 所有元素
媒体: 视觉
计算值: 长度和百分比值为绝对值;其他同指定值。

行高指的是文本行的基线间的距离。而基线(Base line),指的是一行字横排时下沿的基础线,基线并不是汉字的下端沿,而是英文字母x的下 端沿,同时还有文字的顶线(Top line)、中线(Middle line)和底线(Bottom line),用以确定文字行的位置,如图7-17 所示。

图片 24
图7-17 文字的基线

行高与字体尺寸的差称为行距(leading), 如图7-18所示。

图片 25
图7-18 行高与行距

7.3.2 内 容区域、行内框和行框

理论上讲,一行中的每个元素都有一个内容区域,它是由字体尺寸决定的,如图 7-19所示。

图片 26
图7-19 内容区域

行内元素会生成一个行内框(inline box),行内框只是一个概念,它无法显示出来,但是它又确实存在。在没有其他因素影响的时候,行内框等于内容区域,而设定行高则可以增加或者减少行内框 的高度,即:将行距的值(行高-字体尺寸)除以2,分别增加到内容区域的上下两边,如图7-20所示。

图片 27
图7-20 行内框与行高

由于行高可以应用在任何元素上,因此同一行内的若干元素可能有不同的行高和行内 框高,例如有如下代码,其显示如图7-21所示。

<p style=”line-height:20px;”>行高20px。<strong style=”line-height:50px;”> 行高50px。</strong><span style=”line-height:30px;”>行高30px。</span></p>

图片 28
图7-21 行内框与行框

这里又有一个新的概念——行框(line box)。同行内框类似,行框是指本行的一个虚拟的矩形框,其高度等于本行内所有元素中行高最大的值。因此,当有多行内容时,每行都会有自己的行框,如图 7-22所示。

图片 29
图7-22 多行内容的行框

提示:理解行框和行内框的概念对于学习本章 [7.4垂直对齐:vertical-align属性]一节的内容非常重要。
注意:行框的高度只同本行内元素的行高有关,而和父元素的高度(height)无关。

7.3.3 行 高的计算与继承

以em、ex和百分比为单位的行高,其基数是元素本身的字体尺寸。例如有代码如 下:

<p style=”font-size:20px;line-height:2em;”>字高20px,行高2em。</p> <p style=”font-size:30px;line-height:2em;”>字高30px,行高2em。</p>

2个段落的行高都为2em,但是字体大小不同,因此显示如图7-23所示。

图片 30
图7-23 行高的计算

行高可以设定得比字体高度小,此时多行的文字将叠加到一起,例如有如下代码,其 显示如图7-24所示。

p { font-size : 20px; line-height :10px; }

style="font-family: 'courier new', courier;"><p>字高20px,行高10px。此时多行的文字将叠加到一 起。</p>

图片 31
图7-24 比字体高度小的行高

行高是可继承的,但是继承的是计算值,例如有如下代码:

p { font-size :20px; line-height : 2em; }
p span { font-size : 30px; }

style="font-family: 'courier new', courier;"><p>字高20px。<span>字高 30px。</span></p>

<p>元素的行高2em,字体尺寸为20px,因此计算值为 40px,虽然<span>元素本身的字体尺寸为30px,不过其继承的行高仍为40px。但是在不同的浏览器内显示的效果却不尽相同,如图 7-25所示。

图片 32
图7-25 行高的不同表现

由于继承的是计算值,因此当元素内的文字字体尺寸不一样的时候,如果设定固定的 行高很可能造成字体的重叠,例如有如下代码,其显示如图7-26所示。

p { font-size : 20px; line-height : 1em; }
p span { font-size : 30px; }

style="font-family: 'courier new', courier;"><p>字高20px,行高1em,当文本为多行时可能会发生文字重 叠的现象。<span>字高30px。</span></p>

图片 33
图7-26行高继承造成文字叠加

为了避免这种情况,可以为每个元素单独定义行高,但是这样很烦琐,因此可以定义 一个没有单位的实数值作为缩放因子来统一控制行高,缩放因子是直接继承的,而不是继承计算值。例如修改上例中的行高 为:

p { line-height : 1; }

则上例中的XHTML代码显示如图7-27所示。

图片 34
图7-27缩放因子对行高的影响

当内容中含有图片的时候,如果图片的高度大于行高,则含有图片 行的行框将被撑开到图片的高度,如图7-28所示。

图片 35
图7-28 含有图片的行

注意:图片虽然撑开了行框,但是不会影响行 高,因此也不会影响到基于行高来计算的其他属性。
提示:当行内含有图片的时候,图片和文字的垂直对齐方式默认是基线对齐,关于垂直对齐将在本章[7.4 垂直对齐:vertical-align属性]一节中讨论。

7.3.4 浏 览器的差别与错误

浏览器在显示的时候往往会有自己的表现形式,例如在Opera内,行高将按照 CSS定义的将行距除以2增加到内容区域的上下两边,而IE和Firefox则不是完全平分,如图7-29所示。

图片 36
图7-29 不同浏览器对行高的显示

不过,相差的1至2个像素在实际显示中一般不会有太大的影响,因此可以忽略不 计。比较严重的错误是IE 6.0对于含有图片或者表单元等可替换行内元素的行高失效的问题,不过,在IE 7.0中已经修正了这个错误,但是其表现同其它浏览器也不相同。例如有如下代码,其显示如图7-30所示。

#lineHeight4 p { line-height : 60px; }
#lineHeight4 fieldset{ border : 0; }

<div id=”lineHeight4″> <p>内容含有图片在[IE 6]内浏览line-height将失效。<img src=” alt=”图片” width=”88″ height=”31″ /></p> <form id=”testForm” action=”#”> <fieldset> <p><label for=”test1″>表单元素</label>< input type=”text” maxlength=”16″ value=”IE6内行高失效” /></p> </fieldset> </form> </div>

图片 37

图7-30 包含替换元素的行高在IE内失效

由图7-30读者可以发现,IE 7.0中,将半行距分别加在了图片的上下,而由于图片默认是基线对齐,因此文字的基线下移了,这显然不符合CSS中的规定。

对于IE 6.0中行高失效的问题,需要使用CSS Hack手段来针对IE 6.0设定替换元素的上下补白来修正。

提示:关于针对IE 6的CSS Hack,请参见本书[第16章:浏览器与Hack]。

7.3.5 应 用:单行文字在垂直方向居中

在网页设计中,往往为了突出标题而添加背景图案,如图7-31所示。

图片 38
图7-31 包含背景图片的标题

假设此标题的XHTML代码如下:

<div id=”#sample”> <h2>热门帖大盘点</h2> …… </div>

此时如果只设定<h2>的背景图片和高,则文字会偏上,如图 7-32所示。

图片 39
图7-32 未设定行高的标题文字

针对这个现象,一般只需要设定与高度相等的行高即可,相关代码如下:

#sample h2 { height : 31px; line-height : 31px; …… }

此时在浏览器内文字已经在垂直位置上居中显示,如图7-33所示。

图片 40
图7-33 设定行高后的标题文字

此方法同样可以运用在其他需要文字垂直居中显示的地方,例如列表项、导航条等 等。

上一小节讲解了行高与单行纯文字的垂直居中,而如果行内含有图片和文字,在浏览 器内浏览时,读者可以发现文字和图片在垂直方向并不是沿中线居中,而是沿基线对齐,如图7-34所示。

图片 41
图7-34 文字和图片内容默认垂直对齐方式为基线对齐

这是因为,元素默认的垂直对齐方式为基线对齐(vertical-align: baseline)

line-height延伸出的问题

现在为止,我介绍了两个概念:content-arealine-box。如果你看的很仔细,你就会发现我虽然说过一个line-box的高度是根据它的子节点的高度计算出,但我并没有说它的子节点content-area的高度。这两者有很大不同。

可能这听起来很奇怪,一个内联元素有两个不同的高度:content-area 的高度和virtual-area 高度(我发明了这个术语virtual-area,因为这个高度不可见,但你在现在的规范里找不到这个词)。

  • (如前所述)content-area 的高度由字体度量值来定义。
  • virtual-area 高度就是line-height,它就是用来计算line-box的高度**

图片 42

图6:内联元素的两种不同高度

也就是说,人们通常的看法,即line-height是基线之间的距离,这一观点是错误的。在CSS中,这并不成立注3。

图片 43

图7:CSS里,line-height并不是基线直接的距离。

virtual-areacontent-area之间的计算高度差异称为行距。 这个行距一半在content-area的顶部,另一半在底部。 因此content-area始终位于virtual-area的中间

根据行距的计算值不同,line-heightvirtual-area)可以等于,大于或小于content-area。 在比virtual-area更小的情况下,行距为负,所以line-box在视觉上小于其子节点。

还有其他几种内联元素。

  • 被替换的内联元素,(,, ``等等.)
  • inline-block 和所有 all inline-* 的元素
  • 参与特定格式化内容的内联元素(例如,在flexbox元素中,所有flex元素都是blocksified

对于这些特定的内联元素,高度是根据heightmarginborder这些属性计算出的。 如果heightauto,那么就使用line-heightcontent-area严格等于line-height

图片 44

图8:内联替换的元素,inline-block、inline-*和blocksified的元素的内容区域等于其高度或行高

不过,我们面临的问题仍然是:line-heightnormal值是多少? 可以在字体度量值中找到问题的答案,也就是content-area的高度计算。

让我们回到FontForge。 Catamaran的em单位是1000,但是我们看到各种不同升部和降部的值:

  • 生成的升部/降部: 升部是770,降部是230。用于绘制字符。(表OS/2
  • 度量的升部/降部: 升部1100,降部是540。用于绘制 content-area的高度
  • 度量线距。在 line-height: normal时使用,在升部和降部之间的距离(表“hhea”)。

在这个例子中,Catamaran字体定义了0单位线距,所以line-height:normal将等于content-area,它是1640单位,或1.64

相比而言,Arial字体定义了2048个单位的大小,1854的升部,434的降部和67的线距。 这意味着font-size:100px会生成一个112px(1117个单位)的content-area和一个115px(1150个单位或1.15个)的line-height:normal。所有这些度量值都是字体特有的,由字体设计者设置。

很明显,设置line-height: 1并不好。我要提醒你,无单位值是和font-size相关的,而不是content-area相关,而正是处理比content-area小的virtual-area的情况才是许多问题的起源。

图片 45

图9:line-height: 1,产生的line-box比content-area更小。

但这还不仅仅是line-height:1的问题。我的电脑上安装了1117种字体(是的,我安装了所有的字体从Google Web字体,1059种字体,大约95%,计算出的line-height都大于1。他们的line-height从0.618到3.378不等。你没看错,是3.378!

line-box计算的小细节:

  • 对于内联元素, paddingborder会增加背景区域,但不会增加content-area的高度(也不是line-box的高度)。 因此content-area并不总是在屏幕上看到的内容。margin-topmargin-bottom无效。
  • 对于替换型的内联元素,inline-blockblocksified inline元素来说,paddingmarginborder增加的是height,也就是content-arealine-box的高度。

##vertical-align:一个统领全局的属性#

之前我并没有提到vertical-align属性,尽管它是计算line-box高度的一个重要因素。 甚至可以说**vertical-align可能在内联内容格式化上有着重要作用。

vertical-align的默认值是baseline。你还记得字体指标里升部和降部吗? 这些值确定基线在哪里,也确定他们的比例。由于升部与降部的比例很少为50/50,因此可能会产生一些比如对兄弟节点的影响。

还是从代码看起:

XHTML

<p> <span>Ba</span> <span>Ba</span> </p>

1
2
3
4
<p>
    <span>Ba</span>
    <span>Ba</span>
</p>

CSS

p { font-family: Catamaran; font-size: 100px; line-height: 200px; }

1
2
3
4
5
p {
    font-family: Catamaran;
    font-size: 100px;
    line-height: 200px;
}

这个``

元素含有两个互为兄弟节点。他们继承了font-family, font-size 以及固定 line-height的属性。他们的基线会相同,并且这两个元素的line-box高度都和他们的line-height行高相同。

图片 46

图10: 相同的字体,基线相同,万事大吉

但如果第二个元素的font-size变小了呢?

CSS

span:last-child { font-size: 50px; }

1
2
3
span:last-child {
    font-size: 50px;
}

听上去这可能很奇怪,默认基线对齐方式可能会导致一个更高(!)的line-box,如下图所示。你需要了解的是,line-box的高度是从其子节点的最高点到其子节点的最低点计算出来的。

图片 47

图11:较小的子元素会使line-box高度增加

这可能是[尽量使用line-height无单位值的依据](http://allthingssmitty.com/2017/01/30/nope-nope-nope-line-height-is-unitless/),但有时我们也需要固定值来[创建一个完美的垂直对齐的用例](https://scotch.io/tutorials/aesthetic-sass-3-typography-and-vertical-rhythm#baseline-grids-and-vertical-rhythm,但有时我们也需要固定值来[创建一个完美的垂直对齐的用例]()) 其实,无论你怎么选,都会遇到内联元素对齐的麻烦

让我们看看另一个例子。一个line-height:200px的``

标签,包含一个元素,子元素继承了line-height的值。

XHTML

<p> <span>Ba</span> </p>

1
2
3
<p>
    <span>Ba</span>
</p>

CSS

p { line-height: 200px; } span { font-family: Catamaran; font-size: 100px; }

1
2
3
4
5
6
7
p {
    line-height: 200px;
}
span {
    font-family: Catamaran;
    font-size: 100px;
}

line-box有多高? 我们的期望值应该是200px,但事实并非如此。其中的问题是``

有自己的字体,不同于`font-family`(默认为`serif`)。

之间的基线可能会有所不同,因此line-box的高度比我们预期的高。这是因为浏览器进行计算时,会以每行line-box的一个零宽度字符开始,这一规范称为strut。

一个看不见的字符,带来看得见的效果

我们再回过头来看一下之前提到兄弟节点的问题。 图片 48

图12:每个子元素都是对齐的,因为其line-box都从一个看不见且没有宽度的字符计算出的。

但是基线对齐就不管用了。但是用vertical-align: middle可以解决这个问题么?规范里提到, middle意思是垂直方向上父节点的基线加上一半的x子高的总高度的中部对齐。基线比例是不同的,X子高的比例一样,所以middle对齐并不可靠。更糟糕的是,在大多数情况下,middle绝对不会在正中间。有太多因素会影响对齐,无法通过CSS设置这些因素(x字高,升部/降部的比例等等)。

附注:还有4个其他值,在某些情况下可能有用:

  • vertical-align:top/bottom对齐到line-box的顶部或底部
  • vertical-align:text-top /text-bottom对齐到content-area的顶部或底部

图片 49

图13:Vertical-align对应四种值的情况

注意,在所有的情况下,都会对齐virtual-area,也就是那个不可见的高度。看一下这个简单的例子,使用vertical-align:top不可见的line-height可能会产生奇怪但并意料之中的结果

图片 50

图14:垂直对齐可能会产生奇怪的结果,但是当你把行高可视化后,结果其实是意料之中的

最后,vertical-align也可以是提高或降低与基线相关的数值的值。最后这个值可能会派上用场。

2,行内框盒子模型

CSS 棒极了

我们已经讨论了line-heightvertical-align的工作机制,那么问题来了:字体度量值是否可以用CSS控制?简单来说:不能,哪怕我十分希望可以。

不过无论如何,我们可以尝试下。字体度量值是常量,所以我们应该能够利用一下。

举个例子,假如说我们要使用Catamaran字体的文字,让文字高度高达正好是100像素。似乎是可行的,计算一下好了。

首先,我们用CSS自定义属性设置字体指标注4,然后通过计算font-size以获得100px的高度。

CSS

p { /* font metrics */ --font: Catamaran; --fm-capitalHeight: 0.68; --fm-descender: 0.54; --fm-ascender: 1.1; --fm-linegap: 0; /* desired font-size for capital height */ --capital-height: 100; /* apply font-family */ font-family: var(--font); /* compute font-size to get capital height equal desired font-size */ --computedFontSize: (var(--capital-height) / var(--fm-capitalHeight)); font-size: calc(var(--computedFontSize) * 1px); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
p {
    /* font metrics */
    --font: Catamaran;
    --fm-capitalHeight: 0.68;
    --fm-descender: 0.54;
    --fm-ascender: 1.1;
    --fm-linegap: 0;
 
    /* desired font-size for capital height */
    --capital-height: 100;
 
    /* apply font-family */
    font-family: var(--font);
 
    /* compute font-size to get capital height equal desired font-size */
    --computedFontSize: (var(--capital-height) / var(--fm-capitalHeight));
    font-size: calc(var(--computedFontSize) * 1px);
}

图片 51

图15:大写字符的高度正好是100px

很简单,不是吗? 但是,如果我们希望做到视觉上文本居中的效果,那么剩余的空间应该是需要平均分配在“B”字母的顶部和底部?为了实现这一点,我们必须基于升部/降部的比例来计算 vertical-align

首先,计算line-height:normalcontent-area的高度:

CSS

p { … --lineheightNormal: (var(--fm-ascender) var(--fm-descender) var(--fm-linegap)); --contentArea: (var(--lineheightNormal) * var(--computedFontSize)); }

1
2
3
4
5
p {
    …
    --lineheightNormal: (var(--fm-ascender) var(--fm-descender) var(--fm-linegap));
    --contentArea: (var(--lineheightNormal) * var(--computedFontSize));
}

然后,我们需要:

  • 大写字母底部到底部边缘的距离
  • 大写字母顶部到顶部边缘的距离

就像这样:

CSS

p { … --distanceBottom: (var(--fm-descender)); --distanceTop: (var(--fm-ascender) - var(--fm-capitalHeight)); }

1
2
3
4
5
p {
    …
    --distanceBottom: (var(--fm-descender));
    --distanceTop: (var(--fm-ascender) - var(--fm-capitalHeight));
}

现在我们就可以计算vertical-align的值了,也就是距离乘以计算后font-size之间和底部的差值。 (我们必须将此值应用到内联子元素上)。

CSS

p { … --valign: ((var(--distanceBottom) - var(--distanceTop)) * var(--computedFontSize)); } span { vertical-align: calc(var(--valign) * -1px); }

1
2
3
4
5
6
7
p {
    …
    --valign: ((var(--distanceBottom) - var(--distanceTop)) * var(--computedFontSize));
}
span {
    vertical-align: calc(var(--valign) * -1px);
}

最后,我们要设置所需的line-height,并计算如何保持垂直对齐:

CSS

p { … /* desired line-height */ --line-height: 3; line-height: calc(((var(--line-height) * var(--capital-height)) - var(--valign)) * 1px); }

1
2
3
4
5
6
p {
    …
    /* desired line-height */
    --line-height: 3;
    line-height: calc(((var(--line-height) * var(--capital-height)) - var(--valign)) * 1px);
}

图片 52

图16: 具有不同行高的例子。但文字都在中间。

现在再把一个和字符“B”等高的图标加进去就很容易了

CSS

span::before { content: ''; display: inline-block; width: calc(1px * var(--capital-height)); height: calc(1px * var(--capital-height)); margin-right: 10px; backgroundnull:url(''); background-size: cover; }

1
2
3
4
5
6
7
8
9
span::before {
    content: '';
    display: inline-block;
    width: calc(1px * var(--capital-height));
    height: calc(1px * var(--capital-height));
    margin-right: 10px;
    background: url('https://cdn.pbrd.co/images/yBAKn5bbv.png');
    background-size: cover;
}

图片 53

图17: 图标和字符等高

看看JSLint的结果

请注意,此测试仅用于演示目的。你不能依赖这一方法。原因有很多:

  • 除非字体指标是不变的,浏览器中的计算不是 ¯⁠_⁠(ツ)⁠_/⁠¯
  • 如果字体未加载,则默认字体可能具有不同的字体度量,并且处理多个值的计算逻辑将很快变得难以管理。

<p>这是一个单行文字,这里有一个<span>内容区</span>标签。</p>

供你带走的部分#

现在我们学习到了:

  • 内联元素的格式化真的很难理解
  • 所有的内联元素都有两种高度

content-area(基于度量值) virtual-arealine-height行高) ** 毫无疑问,这两个高度都不能可视化。(如果你是一个devtools开发人员并且能够解决可视化问题,那就太棒了)

  • line-height: normal 是基于字体度量值的。
  • line-height: n 可能会创造一个比content-area更小的virtual-area
  • vertical-align不可靠。
  • 一个line-box的高度是基于它的子节点line-heightvertical-align属性来计算的
  • 没有什么好办法能用CSS简单设置字体指标

但我依然爱CSS:)

图片 54

资源

  • 获取字体度量值: FontForge, opentype.js
  • 计算 line-height: normal的值,以及一些比例
  • Ahem, 一种帮助你知道字体是如何构成的字体库
  • 另一篇更深入的教程,解释 内联元素格式化
  • 有一个帮助设置垂直对齐的未来规范:Line Grid module
  • Font Metrics API Level 1, 一个有趣点子的合集

  • [注1]不管你怎么选,都不是重点↩
  • [注2]这并不完全是这样的。↩
  • [注3]在其他编辑软件中,这可能是基线间的距离。 Word或Photoshop就是这样。主要区别在于第一行也受CSS影响↩。
  • [注4]您还可以使用预处理器中的变量,不需要自定义属性↩

    2 赞 5 收藏 2 评论

图片 55

图一

“内容区域” (content area)是围绕文字的盒子,我们可以看做是鼠标在选中文字区域的大小,它的大小只和font-size有关,可以看做是图一中的文字被鼠标选中的区域,也就是选中的“个单行文字”的区域。

“内联盒子”(inline boxs)不会让文字成块显示,而是排列成一行。由内联元素包裹的文字如span标签包裹的“内容区”,可以称之为“内联盒子”,而没有内联元素包裹的部分,我们可以看做是“匿名内联盒子”。“内联盒子”可以看做图一中span标签内的“内容区”区域,而“匿名内联盒子”可以看做红色虚线包裹的内容。

“行框盒子”(line boxs),每一行都是一个“行框盒子”,行框盒子由一个个匿名和非匿名内联盒子组成。可以看做图一中最外面红色实线包裹的区域。

“包含盒子”(containing box),此盒子由一个个“行框盒子组成”。

3,行高的高度机理

行高影响无处不在,即便是单行文字也不例外。

单行文字的高度表现只是受到line-height的影响,而主要是受到内容区域和行间距的影响。

单行文字行高:

line-height = 内容区域高度 行间距高度

那么:

行间距 = line-height - 内容区域高度

我们平常看到的文字上部与“行框盒子”的顶部之间的距离就是半行间距。

4,行高的单位

(1),number

例如:

line-height:2;

font-size:20px;

那么此时文字占据的高度为20*2=40px

(2),length

例如:

font-size:20px;

line-height:20px;

line-height:2em;

line-height:3rem;

line-height:3pt;

以px为单位有一个固定的值,而其余的需要结合浏览器默认尺寸进行换算或者body的font-size属性来计算。

(3),%

<div>

    文字文字

    <p>这是p标签</p>

</div>

div{

font-size:20px;

line-height:150%;

}

p{

font-size:50px;

}

那么“文字文字”的行高为30px,内部p标签行高也是30px,而不会根据子元素重新计算行高。

意思就是说当设置行高为百分比的时候,父元素根据font-size计算的行高继承给子元素,子元素不会根据font-size重装计算行高,一般不常用。

(4),normal

根据浏览器默认line-height属性来设置行高。

(5),inherit

行高继承IE8

继承父元素的行高设置,通常是应用在一些input和button标签。

5,line-height的应用

(1),消除容器中图片与底部的间距

图片 56

图二

产生原因:

内联元素默认基线对齐,空白标签内含有空白幽灵节点,相当于图片和一个文字对齐,根据vertical-align:baseline,所以图片底部存在间距。

这里的幽灵空白节点我们可以理解成一个字母c,因为是基线对齐,且父元素没有设置固定高度,所以父元素高度由内容填充,由于c要与图片基线对齐,所以就会在下边缘。

当父元素设置固定的高度时,单纯div内包含图片和字母c,默认图片与文字基线对齐,图三中c就相当于幽灵空白节点。

图片 57

图三

消除方法

1,让图片块状化

2,图片vertical-align:bottom

3,让匿名空白节点line-height:0

(2),小图标大文字

<i class='icon'></i>

<span>这是span标签内的文字</span>

span{

line-height:30px;

vertical-align:middle;

}

i{

vertical-align:middle;

}

(3),图片水平垂直居中

图片 58

图三

图片 59

图四

原理:

空白div内存在空白幽灵节点(看不见摸不着但存在空白元素中,例如图四中的)。

当设置text-align的时候,内联元素文字和图片会居中显示,我们让空白幽灵节点的行高与div高度一致,这样就可以实现垂直居中,图片和幽灵空白节点默认基线对齐,这时图片将偏上显示,我们设置图片的vertical-align为middle就可以实现图片近似居中的效果了。

如果想让图片完全垂直居中,我们可以让div的font-size:0,原因是不同字体的显示效果不同,有的下沉,有的刚好中线对齐,当font-size:0的时候,文字就变成一个点了,也就不存在不同字体的差异了。

(4),多行文本垂直居中

图片 60

图五

图片 61

图六

原理:

我们可以把span看做是图片,这样原理就和图片垂直居中原理大同小异了。就是需要将span的元素display设置成inline-block,并且重置line-height和text-align。

为何display不能是inline属性,个人观点,如果还是inline元素的话,由于此时父元素的line-height过高,子元素设置的行高很小就没有作用(因为line-height达不到父元素行高的高度,所以看上去好像是无效的),类似于margin中的由于浮动或者绝对定位的无效的原因,我在另外margin篇有介绍,css中margin的深入了解,如果有兴趣可以去看看,如果设置子元素line-height设置很大的话是有作用的,所以只能让span元素为inline-block元素,inline-block具有包裹性,所以呈现出图六效果。

如果容器是自适应高度的,无法获得高度,那么我们可以让外部容器为表格元素居中。

本文由星彩网app下载发布于前端技术,转载请注明出处:深入理解CSS,css中补充的line

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。