line-height和vertical-align精讲

《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>

image-20211204000802117

line-height的作用是显而易见的,指定纯数字,表示行高为当前字体大小的几倍。

行高的构成

line-height其实是一个非常简单,但是却有非常容易用错的属性,因为它可以作用于所有的元素,但是如果能用好,又会是神来之笔,要想用好line-height,我们首先要知道line-height是如何构成的。这里,我们先以文字为例进行说明:

image-20211225214530843

上图中,绿色框里面包裹的是一个行内元素,我们可以看到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>

其渲染结果如下:

image-20211219195019268

我们把div的line-height设置成了18px,而它的第33行的子元素的line-height为30px,这个时候我们观察一下第一个div的高度,如下图所示:

image-20211219195208558

第一个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元素的字体大小设置成和行高一样,其渲染效果如下:

image-20211218020146250

我们再次观察一下第一个div的高度:

image-20211218213405503

我们发现其高度仍然是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 简体中文&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
        </span>
</div>
</body>
</html>

其效果如下图所示:

image-20211219202457918

上面的例子中,我们把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>

image-20211219203443479

下文我们即将就会介绍文字的垂直对齐方式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>

image-20211219203827033

可以看到,我们把图片的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>

a

而我们为一个行里面的行内元素设置vertical-align的时候其实就是在指导这些行内元素和line-box中的匿名行内元素的对齐方式,所以接下来的实例中,为了方便面说明,我们会在示例代码中加一个“辅助元素”来帮助我们理解。

  • 根据line-box的基线来分布元素的baseline,如下的几种写法都属于这种情况

    baselinesubsuperpercentagelength
    与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>
    

    image-20211225220504311

  • 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>
    

    image-20211225220431911

  • 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>
    

    image-20211225221142489

  • 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>
    

    image-20211225221425257

了解了上面的基本对其行为之后,我们把上面介绍text-top、text-bottom以及介绍top、bottom这两个例子中的辅助匿名元素x给去掉之后,得到的渲染效果如下:

image-20211225221719760

image-20211225221654013

可见,我们的辅助元素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>

image-20211225222340638

这个时候,我们单独分析第1、2、3、4段的对齐行为都是符合我们的预期的,但是我们难以理解的是为什么辅助元素x会被顶到line-box最下方的位置。

这是因为,在某些情况下,为了满足vertical-align的布局设置,line-box的基线会发生移动。

在上面的例子中,第四段的字体是最大的,它为整个line-box贡献了最大行高,这个时候无论我们怎么设置它的对其方式,它在整个line-box中都是“顶天立地”的存在,这个时候为了让其他的行内元素不超出行的范围,匿名元素的基线就会被平移到让所有元素都在行内的地方。

比如我们把第24行的注释打开,其渲染效果如下:

image-20211225223703798

这个时候我们发现,受这个的影响,x被上移,第五段刚好在line-box之内,而受这个的影响,第一段和第三段的位置也发生了响应的变化,因为根据我们设置的vertical-align,第一段需要与x的中线对齐,而第三段需要与x的底对其。

总结

line-height和vertical-align的行为有时确实令人迷惑,不过只要我们能够理解行高的构成和vertical-align的对其对象是行内元素和line-box中的匿名行内元素中线,这个时候它的行为就变得不再那么难以理解了。

以上就是我对line-height和vertical-align的基本理解,感谢你耐心读完。本人深知技术水平和表达能力有限,如果文中有什么地方不合理或者你有其他不同的思考和看法,欢迎随时和我进行讨论(laomst@163.com)。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

劳码识途

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值