vertical-align:middle的简单探讨

The vertical-align property specifies the vertical alignment of an inline or table-cell box.

MDN解释了vertical-align属性描述了内联元素和表格单元的垂直排列方式。其默认值是baseline。
显然的是,vertical-align属性不能作用于display:block的元素上。但实际使用时还是常常有困惑。让我们来看一下。

vertical-align属性的使用

<div class="parent">
  <div class="child child1"></div>
  <div class="child child2"></div>
  <div class="child child3"></div>
</div>
<style>
.parent {
  background: blue;
  vertical-align: middle;
}
.child {
  display: inline-block;
  width: 20%;
  background: yellow;
}
.child1 {
  height: 10px;
  
}
.child2 {
  height: 20px;
  
}
.child3 {
  height: 30px;
}
</style>

如以上代码所示,parent元素的三个子元素高度不一,这时需求要求将这三个元素垂直居中对齐,我第一次就是这样写的,于是就得到这样的结果。嗯,完全无效。

《vertical-align:middle的简单探讨》 vertical-align-error.png

然后就去Google这个问题”vertical-align not working”,然后就能够看到这个提问CSS vertical-align: middle not working
回答中的代码的关键就是将vertical-align属性移到了需要对齐的子元素上。所以上面的代码做以下修改就可以达到目的。

<style>
.parent {
  background: blue;
  /* vertical-align: middle; */
}
.child {
  display: inline-block;
  width: 20%;
  background: yellow;
  vertical-align: middle;  /* 在子元素上增加这个属性 */
}
……
</style>

得到预期中的结果,如下图

《vertical-align:middle的简单探讨》 vertical-align-right.png

注意点二: vertical-align: middle是怎样工作的

按照相对自然的想法,猜测垂直居中属性的设置是将子元素的中轴线与父元素高度的一半位置对齐。
那么如果对上面的DOM中的child1单独设置垂直居中

<style>
.child1 {
  height: 10px;
  vertical-align: middle;  /* 单独设置 */
}
</style>

理想中应该是这样的效果

《vertical-align:middle的简单探讨》 what-I-thought

而实际上,是这样的,我们可以看到,垂直居中属性的设置仅仅是让第一个黄方块下移了1px。

《vertical-align:middle的简单探讨》 what-I-saw

我们可以再对第三个方块单独设置垂直居中试试,嗯效果变得更明显了一些。

《vertical-align:middle的简单探讨》 child3-vertical-align.png

第一次看到这样的效果很让人吃惊,因为这种效果看起来就像是,将前两个方块的vertical-align属性改变了——设置一个元素的css属性,可以影响其兄弟元素的对应css属性?!多么可怕的猜测。
出于对于CSS基础原则的理解,这个猜测一定是荒谬的。所以让我们结束猜测,去看看实际上垂直居中属性是怎样起作用的。

vertical-align: middle
Aligns the middle of the element with the baseline plus half the x-height of the parent.
(将元素的中轴线与父元素的基线加x-height的一半的高度对齐)

看到对于vertical-align的解释,会发现和想象中的可能不太一样。我们先来看一下拓展知识。

baseline是什么? x-height又是什么?

抄一张来自Wikipedia的图,

《vertical-align:middle的简单探讨》 baseline.png

In European and West Asian typography and penmanship, the baseline is the line upon which most letters “sit” and below which descenders extend.
(在欧洲和西亚的印刷和书法领域,基线就是大部分字母“”的位置,同时是下行字母(descender)下半部分延伸的出发线)

In typography, the x-height or corpus size is the distance between the baseline and the mean line of lower-case letters in a typeface. Typically, this is the height of the letter x in the font.
(在印刷术中,x-height就是小写字母的基线和mean-line之间的距离。小写字母x的字体高度就是典型的x-height.)

除了维基,也可以参考英语字体的基础知识

拓展知识部分结束,看完拓展知识我们可以顺手解决的一个额外的问题。

一个额外的问题

之前演示错误的垂直居中设置方法时,我们看到了下面这张图(这张被放大了)。很明显的,在三个黄色方块下还有一段空隙,这段空隙是什么

《vertical-align:middle的简单探讨》 what-is-the-bottom-part.png

现在我们知道vertical-align的默认值是baseline,又知道了baseline的含义,那么结果就显而易见了,这段空隙就是为下行字母的下行延伸部分所预留的descender height。下图就是很好的体现。(qypg是父元素中的文本内容)

《vertical-align:middle的简单探讨》 with-descenders.png

那么,如果将父元素的高度也限定为30px,并同样在父元素中塞进下行字母qypg。

<div class="parent">
  <div class="child child1"></div>
  <div class="child child2"></div>
  <div class="child child3"></div>
  qypg
</div>
<style>
.parent {
  background: blue;
  height: 30px;  /* 与三个方块中最高的child3一致 */
}
……
</style>

我们得到了这样的结果。嗯,下行字母的延伸部分爆炸了。引申出一个问题:块元素的baseline是怎样确定的?

《vertical-align:middle的简单探讨》 descender-height-exploded.png

回到问题

我们现在回到这个问题,出现这样的排列现象的原因是什么。

《vertical-align:middle的简单探讨》
《vertical-align:middle的简单探讨》 vertical-align.png

我们以第二幅图的排列为例尝试解释。
首先可以肯定的是,第三个方块的vertical-align属性的设置不会影响其兄弟元素的这个属性,因此前两个方块的vertical-align属性依然是默认值baseline。
那么原因就是父元素的baseline发生了变化

《vertical-align:middle的简单探讨》 show-baseline.png

可以在上图中看到,父元素的文本内容中字母x的底部和左边两个黄方块的底部高度是一致的,这也就是baseline所在的位置。而短横划线所在的高度就是
(height of baseline + x-height / 2)的值,也就是第三个方块的中轴所在的高度。如下图的虚框,高度为15px;

《vertical-align:middle的简单探讨》 image.png

以上的问题基本解决了,造成问题的主要原因是对基础概念的不熟悉,包括vertical-align的作用原理与英文字体的相关知识。
以及绕不开的这个问题:块元素的baseline是怎样确定的?

* baseline探讨预热

<div class="grandparent">
  <div class="parent parent1">
    <div class="child child1"></div>
  </div>
  <div class="parent parent2">
    <div class="child child2"></div>
  </div>
</div>
<style>
.grandparent {
  background: blue;
}
.parent {
  width: 40%;
  height: 40px;  /* 有与没有的区别*/
  background: white;
  margin: 10px;
  display: inline-block;
}

.child {
  display: inline-block;
  width: 100%;
  height: 10px;
  background: yellow;
}
.child1 {
  vertical-align: middle;  /* 有与没有的区别 */
  height: 30px;
}
</style>
    原文作者:制杖魔导师
    原文地址: https://www.jianshu.com/p/38e47210d8bb
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞