一文读懂vertical-align

921 阅读8分钟

vertical-align作用

指定元素的垂直对齐方式,只对行内元素有效,就是display的属性为inline、inline-block、inline-table,再加一个table-cell (<td></td>)的元素,

行内元素的几条线和行高

image-20211025145903994.png

图片来自:www.zhangxinxu.com/wordpress/2…

上行线

图中的ascent

上行线和盒子最上边的一小块高度是上行线高度ascender height

下行线

图中的descent

下行线和盒子最下边的一小块高度是下行线高度descender height

基线

图中红色的线baseline,也就是字符X的最下边

中线

图中的 median,也就是x的底部,再往上多一个x-height高度后的那条线。

大意就是:middle指的是基线往上1/2 "x-height"高度。可以近似脑补成字母x交叉点那个位置。

由此可见,vertical-align: middle并不是绝对的垂直居中对齐,我们平常看到的middle效果只是一种近似的效果。原因很简单,因为不同的字体,其在行内盒子中的位置是不一样的,比方说’微软雅黑’就是一个字符下沉比较明显的字体,所有字符的位置相比其他字体要偏下一点。要是vertical-align: middle是相对容器中分线对齐,你会发现图标和文字不在一条线上,而相对于字符x的中心位置对齐,我们肉眼看上去就好像和文字居中对齐了。

行高 line-height

最多的说法是两行字符基线与基线之间的距离,其实也是中线与中线之间的距离,也是上行线与上行线之间的距离,想怎么说就怎么说,高度都是一样的

所以我这样理解:行高是 上行线高度+上行线到下行线之间的高度 +下行线高度

所以,当一个盒子的height=line-height时,文字就会垂直居中显示了

当行高小于height时,文字就偏上显示,(因为行高不够所以偏上显示)

当行高大于height时,文字就偏下显示,(因为行高冒了,所以文字就偏下显示)

vertical-align属性值

操作表格单元格

如果是操作单元格td,表格单元格的值

top:使单元格内边距的上边缘与该行顶部对齐。(就是盒子模型的content的上边缘)

middle:使单元格内边距盒模型在该行内居中对齐。(就是盒子模型的content的中间)

bottom:使单元格内边距的下边缘与该行底部对齐。(就是盒子模型的content的底部)

行内元素值

tip 没有基线的元素,使用外边距的下边缘替代。

baseline

使元素的基线与父元素的基线对齐。

sub

使元素的基线与父元素的下标基线对齐。

super

使元素的基线与父元素的上标基线对齐。

text-top

使元素的顶部与父元素的字体顶部对齐。

text-bottom

使元素的底部与父元素的字体底部对齐。

middle

使元素的中部与父元素的基线加上父元素x-height(译注:x高度)的一半对齐。

length

使元素的基线对齐到父元素的基线之上的给定长度。可以是负数。

1、正值:基线向上移动

2、负值:基线向下移动

percentage

使元素的基线对齐到父元素的基线之上的给定百分比,该百分比是line-height属性的百分比。可以是负数。

1、正值:基线向上移动

2、负值:基线向下移动

例子理解

辨别“行内元素的基线”与“行内元素所在行的基线”

1、行内元素的基线:就是字母x的下边沿,就是上面讲的红色的线 baseline,元素的基线和下行线之间还留有一定的距离,这些距离是留给那些带尾巴的字母或者是汉字的空间,比如j,y,g等等

2、元素所在行的基线:就是所在行的基准元素,对齐时所依据的那条线。把基准元素所在行当作父元素,也就是说,所在行的基线由他的一个子元素--基准元素所决定。

如果基准元素采用中线对齐,那么所在行的基线就是基准元素的中线,如果基准元素采用顶线对齐,那么所在行的基线就是基准元素的顶线。

所以,基准元素依据哪条线对齐,父元素的基线就是哪条。

另外,根据有无vertical-align属性,还可以分为下面三种情况

(1)全部都没有添加vertical-align时,默认以基准元素的基线对齐。

(2)基准元素添加vertical-align,同一行的其他inline box 没有添加,这时,就是上面说的情况,如果基准元素采用中线对齐,那么所在行的基线就是基准元素的中线,如果基准元素采用顶线对齐,那么所在行的基线就是基准元素的顶线。

(3)当基准元素没有添加vertical-align,同一行的其他inline box添加了,这时添加vertical-align属性的inline box 以基准元素的默认的线对齐,代入例子就是,如果其他元素对齐方式改为vertical-align: top,那就对齐基准元素的top线,如果时bottom,就对齐bottom线,以此类推

(4)基准元素和同一行的其他inline box都添加了vertical-align属性,这其实和第三种情况一样,基准元素因为是最高的那一个,无论怎么对齐,都是一样,位置不变,把整一行撑满了,其他元素就以基准元素的线去对齐,该对中线就对中线,该对上线就对上线,以此类推

基准元素

同一行中最高的那个inline box就是这一行的基准元素

如果这个inline-box没有文字,则没有基线,默认基线位置为下外边距的边缘处,没有外边距时就是元素的最下边。

如果有文字,基线就是上面提到的红色线baseline,也即字母x的最下边。

父元素基线计算方式

默认情况下,行内元素的垂直对齐方式都是以基线对齐

  1. 没有文字时,如下图所示

    • 黄色和绿色都是inline box,默认以这一行的基线对齐
    • 这一行的基线就是黄色的基线(因为它在这一行最高,也即是这一行的基准元素)
    • 黄色因为没有文字,默认没有基线,所以以它的下边距的边缘处为基线
    • 所以绿色框就以黄色块(也即这一行的基准元素)的基线对齐,绿色块本身默认以基线对齐,由于它也是没有文字的inline box,所以默认基线也是它的下边距的最外边缘处。最终就成了如下的布局样式。

    注意,inline-block元素间有空格或是换行会产生间隙,使用font-size: 0;可去除

image-20211025161858917.png

<style>
    .father {
        width: 300px;
        border: 1px solid green;
        font-size: 0;
    }

    .son1 {
        display: inline-block;
        width: 50px;
        height: 100px;
        background-color: yellow;
        margin-bottom: 10px;
    }

    .son2 {
        display: inline-block;
        width: 50px;
        height: 20px;
        background-color: blue;
    }
</style>
<body>
    <div class="father">
        <div class="son1"></div>
        <div class="son2"></div>
    </div>
</body>

image-20211025163939676.png

<style>
    .son1 {
        display: inline-block;
        width: 50px;
        height: 100px;
        background-color: yellow;
        margin-bottom: 10px;
    }
</style>
  1. 有文字时,如下图所示
    • 黄色和蓝色都是inline box,默认以这一行的基线对齐
    • 这一行的基线就是黄色的基线(因为它在这一行最高,也即是这一行的基准元素)
    • 黄色有文字,默认基线为上面说到的字母x的最下边,所以本行的基线就是Son1的基线
    • 所以绿色框就以黄色块(这一行的基准元素)的基线对齐,默认以基线对齐,因为绿色框也是有文字的,所以默认基线也是文字的基线。最终就成了如下的布局样式。

image-20211025165244833.png

<style>
    .father {
        width: 300px;
        border: 1px solid green;
        color: red;
    }

    .son1 {
        display: inline-block;
        width: 80px;
        height: 100px;
        background-color: yellow;
    }

    .son2 {
        display: inline-block;
        width: 80px;
        height: 20px;
        background-color: blue;
    }
</style>

<body>
    <div class="father">
        <div class="son1">Son1</div>
        <div class="son2">Son2</div>
    </div>
</body>

3、使用vertical-align实现son2垂直居中

先来看一个效果,如下图,只是在son1增加了一个vertical-align: middle;,但是son2却跑到了中间,这是为什么呢?

我们还按照上面一步步分析一下:

  • son1和son2都是inline box,默认以这一行的基线对齐
  • 这一行的基准元素是黄色块(因为它最高),黄色块有文字,所以基线就是文字的基线,默认以基线对齐
  • 但是主动修改了son1(基准元素)的对齐方式vertical-align:middle,所以整行的对齐方式就变为了以son1(基准元素)的中线对齐。
  • 所以son2的基线就对齐了son1(所在行的基准元素)的中线,就形成了下面的效果。

实际上,son2并没有完全在中间显示,有点偏上,因为son2的基线就是文字的基线,偏下一点,所以要想实现完全居中的效果,可以在son2上也加一个vertical-align: middle

image-20211025172823184.png

实战:使用伪元素和vertical-align: middle实现垂直居中

<style>
    * {
        margin: 0;
    }

    .parent {
        width: 300px;
        height: 300px;
        border: 1px solid red;
        text-align: center;
    }

    .child {
        background: blue;
        width: 100px;
        height: 40px;
        line-height: 40px;
        color: #fff;
        display: inline-block;
        vertical-align: middle;
    }

    .parent::before {
        content: '';
        height: 100%;
        display: inline-block;
        vertical-align: middle;
    }
</style>

<body>
    <div class="parent">
        <div class="child">child</div>
    </div>
</body>

image-20211025174754555.png

分析居中的原理:

  • 在parent增加了一个after伪元素,相当于这个伪元素和child变为了兄弟关系
  • 伪元素after设置为inline-block,高度设置为父元素的高度,child也设置为了inline-block
  • 这时伪元素after和child就变为了处于同一行的inline box
  • 默认以基准元素(也即伪元素after,因为它比较高)的基线对齐
  • 因为伪元素设置了vertical-align: middle属性,所以整行就以伪元素的中线对齐
  • child因为有字,默认基线就是正常行内元素的基线,因为基线偏下,所以也给child增加一个verticle-align: middle
  • 让child的中线和基准元素的中线对齐,最终就实现了垂直居中的效果

参考:

www.jianshu.com/p/ce7e4a997…

www.jianshu.com/p/59f31a170…

juejin.cn/post/684490…

developer.mozilla.org/zh-CN/docs/…

www.zhangxinxu.com/wordpress/2…