《line-height和vertical-align精讲》源站链接,阅读体验更佳~
line-height的行为
- 默认值:normal
- 作用于:所有的元素
- 默认继承:是
- 值集:<数字>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文字对齐</title>
<style>
p {
background: #ddd
}
.one-line {
line-height: 1;
}
.two-line {
line-height: 2;
}
</style>
</head>
<body>
<p class="one-line">
荷塘的四面,远远近近,高高低低都是树,而杨柳最多。<br>
这些树将一片荷塘重重围住;<br>
只在小路一旁,漏着几段空隙,像是特为月光留下的。<br>
树色一例是阴阴的,乍看像一团烟雾;但杨柳的丰姿,便在烟雾里也辨得出。<br>
树梢上隐隐约约的是一带远山,只有些大意罢了。<br>
树缝里也漏着一两点路灯光,没精打采的,是渴睡人的眼。<br>
这时候最热闹的,要数树上的蝉声与水里的蛙声;<br>
但热闹是它们的,我什么也没有。
</p>
<p class="two-line">
荷塘的四面,远远近近,高高低低都是树,而杨柳最多。<br>
这些树将一片荷塘重重围住;<br>
只在小路一旁,漏着几段空隙,像是特为月光留下的。<br>
树色一例是阴阴的,乍看像一团烟雾;但杨柳的丰姿,便在烟雾里也辨得出。<br>
树梢上隐隐约约的是一带远山,只有些大意罢了。<br>
树缝里也漏着一两点路灯光,没精打采的,是渴睡人的眼。<br>
这时候最热闹的,要数树上的蝉声与水里的蛙声;<br>
但热闹是它们的,我什么也没有。
</p>
</body>
</html>
line-height的作用是显而易见的,指定纯数字,表示行高为当前字体大小的几倍。
行高的构成
line-height其实是一个非常简单,但是却有非常容易用错的属性,因为它可以作用于所有的元素,但是如果能用好,又会是神来之笔,要想用好line-height,我们首先要知道line-height是如何构成的。这里,我们先以文字为例进行说明:
上图中,绿色框里面包裹的是一个行内元素,我们可以看到6条线,分别是顶线、文字顶、中线、基线和文字底和底线,而一个行内元素所有的可渲染内容就是顶线和底线之间的部分,如果我们没有为元素设置任何line-height相关的属性,那么行内元素的顶线和底线就会和文字顶已经文字底对其。
-
文字顶和文字底
同时我们也可以看到,为了渲染的美观性,文字顶和文字底并不是直接顶这文字的,而是留有一个空隙,空隙的大小视字体的大小而定,如果字体的大小是12px,那么这个空隙大概是3px。
-
中线
顾名思义,中线就是指行内元素高度的中间位置,也就是顶线和底线正中间的那条线。
-
基线
我们上小学学习英文和拼音的时候应该都是用过四线格,而四线格的第三条线其实就是英文字母的基线,而对于中文这样的文字而言,基线一般就是文字的最底部。
line-height只影响行的高度
我们在介绍line-height的时候提到,line-height可以作用于所有的元素,而且它是可以被继承的,但是,实际上对line-height最敏感的元素是行内元素,当父元素和子元素同时设置了line-height的时候,如果父元素的line-height比它的line-height最大的子元素的line-height还要小的时候,这个元素本身的高度会被子元素撑起来,我们看下面的代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>inline</title>
<style>
.c {
background: aquamarine;
font-size: 18px;
line-height: 18px;
}
span{
background:red;
}
.c1{
line-height: 30px;
}
.c2{
line-height: 8px;
}
.c3{
line-height: 20px;
}
.c5{
line-height: 28px;
}
</style>
</head>
<body>
<div class="c">
<span class="c1">efghijxyz 简体中文</span>
<span class="c2">efghijxyz 简体中文</span>
<span class="c3">efghijxyz 简体中文</span>
efghijxyz 简体中文
<span class="c5">efghijxyz 简体中文</span>
</div>
<div class="c">
另起一行
</div>
</body>
</html>
其渲染结果如下:
我们把div的line-height设置成了18px,而它的第33行的子元素的line-height为30px,这个时候我们观察一下第一个div的高度,如下图所示:
第一个div元素的高度已经被撑大为了30px,而不是我们为其设置的18px。
同时我们也发现了一点,我们为四个span元素设置的line-height都是不一样的,但是这四个span的渲染高度其实是一样的,大家可以观察一下,这四个span元素的高度其实都是24px。
也就是说,line-height并不会影响元素实际内容的渲染高度,就像上面span元素的高度,其实还是由字体大小来决定的。
下面,我们再来做一个实验,我们把上面的代码改为如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>inline</title>
<style>
.c {
background: aquamarine;
line-height: 18px;
font-size: 18px;
}
span{
background:red;
}
.c1{
line-height: 30px;
font-size: 30px;
}
.c2{
line-height: 8px;
font-size: 8px;
}
.c3{
line-height: 20px;
font-size: 20px;
}
.c5{
line-height: 28px;
font-size: 28px;
}
</style>
</head>
<body>
<div class="c">
<span class="c1">efghijxyz 简体中文</span>
<span class="c2">efghijxyz 简体中文</span>
<span class="c3">efghijxyz 简体中文</span>
efghijxyz 简体中文
<span class="c5">efghijxyz 简体中文</span>
</div>
<div class="c">
另起一行
</div>
</body>
</html>
我们把上面所有span元素的字体大小设置成和行高一样,其渲染效果如下:
我们再次观察一下第一个div的高度:
我们发现其高度仍然是30px,这仍然是第37行的span元素的line-height所造成的结果。
但是,仔细观察之后我们发现了一个问题,就是第一个div中的span元素已经溢出了,这就是因为元素的实际渲染高度并不是由元素的line-height决定的,其实际高度还是由元素本身的内容所决定的,对line-height敏感的是行内元素,其效果是撑起了行的高度。
line-height的妙用和问题
上面我们介绍了line-height的基本效果,而line-heigt的这些效果会造成一些问题,同时也造就了line-height的许多妙用,其中最经典的就是利用line-height做内容的垂直居中,已经我们经常遇到的图片3px缝隙问题,下面我们分别来介绍一下
利用line-height做垂直居中
如果我们同时为父元素和子元素设置了行高,而父元素的行高比子元素的行高大,那么父元素多出来的line-height会平均分布在子元素的两侧。
下面,我们先看一下下面的例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>inline</title>
</head>
<body>
<div style="border:solid 1px red;line-height: 120px">
<span style="background:blue;color:#fff;font-size:20px;line-height:60px;">
efghijxyz 简体中文           
</span>
</div>
</body>
</html>
其效果如下图所示:
上面的例子中,我们把div的line-height设置为了120px,其子元素span的line-height为60px,这个时候span的行高不足以撑起div的高度,所以div实际生效的行高就是120px,而从图中我们也可以看出,这个时候子元素span在整个div中是处于中间位置的,这个时候我们就非常容易地利用line-height实现了一个垂直居中的效果。
图片的3px缝隙问题
在上面介绍行高的构成的时候,我们提到了6条线,分别是顶线、文字顶、中线、基线、文字底和底线,对于文字来说,这6条线都是存在的,但是对于一些特殊的行内元素,比如图片,它其实是没有基线和文字顶文字底这一说的,这个时候它的基线就会下移到元素的底线的位置。而当一行中出现一个没有底线的行内元素的时候,这个行内元素的底部就会出现一个缝隙,如下代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>line-height</title>
</head>
<body>
<div style="background:aquamarine">
<span>文字</span>
<img src="favicon.ico"/>
</div>
</body>
</html>
下文我们即将就会介绍文字的垂直对齐方式vertical-align,这里我们先提前说明一下:**当我们没有为元素指定任何vertical-align的时候,其默认的对其方式就是按基线对其。**这个时候,如果一行中既有文字,又有图片的话,那么图片的下方就会出现一条缝隙,出现这样现象的原因就是图片的基线其实就是图片的底线。而我们前文的时候也提到过,为了渲染的效果,文字的文字顶和文字底之间是有一定的距离的,而这个距离的不同根据字体大小的不同会有所不同,上文中我们的字体大小是12px,那么这个缝隙大概就是3px作用,这就是图片3px缝隙问题的成因。
这个问题也非常好解决,只要我们把图片的对其方式修改为按照底线对其,这条缝隙就没有了,如下代码所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>line-height</title>
</head>
<body>
<div style="background:aquamarine">
<span>文字</span>
<img style="vertical-align: bottom" src="favicon.ico"/>
</div>
</body>
</html>
可以看到,我们把图片的vertical-align设置为bottom之后,图片下方的缝隙消失了。
解决缝隙问题我们也可以把图片的display设置为block,这个时候图片独占一行,当然也就不会存在缝隙了,这里我们主要是为了介绍行高,所以把修改图片display的这种方式我们这里就不做过多介绍了。
vertical-align 的行为
上文中我们在介绍图片3px问题的时候已经简单提过文字的垂直对齐,接下来我们就来详细介绍一下它。
- 默认值:baseline
- 作用于:行内元素和表格单元格
- 默认继承:是
- 值集:baseline、top、text-top、middle、text-bottom、bottom、sub、super
上面值集中的baseline、top、middle、bottom这四个值分别对应于我们介绍行高的构成时所介绍的基线、顶线、中线和底线,而sub和super则会移动基线的位置。
-
baseline是所有行内元素的默认对齐方式,如果某行内元素没有基线也没有文字线(如图片、表单、输入框),则此元素的基线就会落到底线上,这也是我们上面介绍的图片3px缝隙问题的原因。
-
top、bottom
top将元素的上方和行框的上方对齐,bottom将元素的下方和行框的下方对齐
-
sub、super
上标和下标通常用于表示注解号、次幂等。但是利用对齐方式的话只是提高元素的基线或者降低元素的基线,并不会修改字体大小,而H5中增加了更加语义化的标签
<sub>
和<sup>
,它们的对其方式默认也是sub和super,因此我们通常是直接使用这两个标签。
关于vertical-align你需要知道
- vertical-align只会影响元素本身,而不是元素内容(除了table单元格)
- 当vertical-align作用在单元格或者display: table-cell的元素上时,只影响单元格而不影响子元素
- vertical-align在表格单元格中只可作用于baseline、top、middle和bottom四个值
多个行内元素有不同的vertical-align时的对齐行为
当在一个行里面,有多个行内元素的时候,如果我们对这多个行内元素施加不同的vertical-align,这个时候这多个行内元素的对其行为往往比较令人费解,大家可以参考一下下面的这篇文章,这篇文章中对vertical-align的行为进行了详细的阐述:
英文原文:https://christopheraue.net/design/vertical-align#vertical-align-acts-on-inline-level-elements-in-a-line-box
中文译文:https://www.cnblogs.com/coolqiyu/p/7292564.html
这里,我进行一个简要的总结。
我们把一行称为一个line-box,而一个line-box中可能会包裹多个行内元素(inline、inline-block、inline-table),通过上文对行高的构成的介绍中,我们可以知道每一个行内元素的都有6条线,而一个line-box其实也有6条线,只不过line-box的这六条线其实就是其匿名行内元素的6条线,也就是其直接包裹的文本子元素的文字的基线、文字顶(顶线)、中线、文字底(底线),如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>line-box的基线</title>
</head>
<body>
<div style="line-height: 100px; border: solid 1px red">
x
</div>
</body>
</html>
而我们为一个行里面的行内元素设置vertical-align的时候其实就是在指导这些行内元素和line-box中的匿名行内元素的对齐方式,所以接下来的实例中,为了方便面说明,我们会在示例代码中加一个“辅助元素”来帮助我们理解。
-
根据line-box的基线来分布元素的baseline,如下的几种写法都属于这种情况
baseline sub super percentage length 与line盒子baseline重合 line盒子baseline下 line盒子baseline上 相对于line-height的大小 绝对长度 如下代码所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>line-box的基线</title> <style> span { font-size: 18px; } </style> </head> <body> <div style="border: solid 1px red"> x <span style="vertical-align: baseline">baseline</span> <span style="vertical-align: sub">sub</span> <span style="vertical-align: super">super</span> <span style="vertical-align: -50%">-50%</span> <span style="vertical-align: 50%">+50%</span> </div> </body> </html>
-
middle 元素的中线和line-box的中线对齐:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>line-box的基线</title> <style> span { font-size: 28px; } </style> </head> <body> <div style="border: solid 1px red"> x <span style="vertical-align: middle">middle</span> </div> </body> </html>
-
text-top:元素的顶线与line-box中匿名行内元素的文字顶(顶线)对其
text-bottom: 元素的底线与 line-box 中匿名行内元素的文字底(底线)对其
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>line-box的基线</title> <style> span { font-size: 28px; border: solid 1px greenyellow; } </style> </head> <body> <div style="border: solid 1px red"> x <span style="vertical-align: text-top">text-top</span> <span style="vertical-align: text-bottom">text-bottom</span> </div> </body> </html>
-
top:元素的顶线和line-box的顶线对其
bottom: 元素的底线和 line-box 的底线对齐
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>line-box的基线</title> <style> span { font-size: 28px; border: solid 1px greenyellow; } </style> </head> <body> <div style="border: solid 1px red"> x <span style="vertical-align: top">top</span> <span style="vertical-align: bottom">bottom</span> </div> </body> </html>
了解了上面的基本对其行为之后,我们把上面介绍text-top、text-bottom以及介绍top、bottom这两个例子中的辅助匿名元素x给去掉之后,得到的渲染效果如下:
可见,我们的辅助元素x并不会影响实际的渲染效果,接下来,我们以下面一个例子来分析一下最终的对齐行为的成因,结束我们对line-height和vertical-align的介绍:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>line-height</title>
<style>
div {
background: aquamarine;
}
span {
border: solid 1px red;
}
</style>
</head>
<body>
<div class="c1">
x
<span style="font-size:18px;vertical-align: middle">第一段</span>
<span style="font-size:38px;vertical-align: top;">第二段</span>
<span style="font-size:64px;vertical-align: text-bottom;">第三段</span>
<span style="font-size:120px;vertical-align: bottom;">第四段</span>
<!-- <span style="font-size:38px;vertical-align: -50%">第五段</span>-->
</div>
</body>
</html>
这个时候,我们单独分析第1、2、3、4段的对齐行为都是符合我们的预期的,但是我们难以理解的是为什么辅助元素x会被顶到line-box最下方的位置。
这是因为,在某些情况下,为了满足vertical-align的布局设置,line-box的基线会发生移动。
在上面的例子中,第四段的字体是最大的,它为整个line-box贡献了最大行高,这个时候无论我们怎么设置它的对其方式,它在整个line-box中都是“顶天立地”的存在,这个时候为了让其他的行内元素不超出行的范围,匿名元素的基线就会被平移到让所有元素都在行内的地方。
比如我们把第24行的注释打开,其渲染效果如下:
这个时候我们发现,受这个的影响,x被上移,第五段刚好在line-box之内,而受这个的影响,第一段和第三段的位置也发生了响应的变化,因为根据我们设置的vertical-align,第一段需要与x的中线对齐,而第三段需要与x的底对其。
总结
line-height和vertical-align的行为有时确实令人迷惑,不过只要我们能够理解行高的构成和vertical-align的对其对象是行内元素和line-box中的匿名行内元素中线,这个时候它的行为就变得不再那么难以理解了。
以上就是我对line-height和vertical-align的基本理解,感谢你耐心读完。本人深知技术水平和表达能力有限,如果文中有什么地方不合理或者你有其他不同的思考和看法,欢迎随时和我进行讨论(laomst@163.com)。