从一个垂直居中的方法深度了解基线与 vertical-align

案例:采用伪元素实现垂直居中

今天在一篇文章中无心看到一个利用伪元素实现垂直居中的方法,费了好大劲理解了它的原理,因而就有了这篇文章。浏览器

这个方法是经过在父元素上添加一个高度 100%、vertical-align: middle的伪元素实现垂直居中的,效果和代码以下:post

<div class="parent">
  <div class="child">child</div>
</div>
复制代码
.parent {
    width: 300px;
    height: 300px;
    border: 1px solid red;
    text-align: center;
}
.child {
    background: blue;
    width: 100px;
    height: 40px;
    display: inline-block;
    vertical-align: middle;
}
.parent::before {
    content: '';
    height: 100%;
    display: inline-block;
    vertical-align: middle;            
}
复制代码

基本概念

在深刻了解以前,先来了解一些基本概念。spa

基准元素

一行 inline 元素中,取行高最高元素的做为基准元素。.net

行内元素的基线

咱们都知道,默认状况下,行内元素的垂直对齐方式为基线对齐。这里的基线(base line)指的是英文字母“x”的下端沿: 3d

图片来源:https://blog.csdn.net/lulujiajiawenwen/article/details/8245201code

举个例子,下图的两个行内元素都是基线对齐的,红色的线就是它们的基线: cdn

<div class="parent">
  <div class="child1">abcxyz</div>
  <div class="child2">efghij</div>
</div>
复制代码
.parent {
  width: 300px;
  height: 100px;
  border: 1px solid blue;
}
.child1 {
  display: inline-block;
  height: 20px;
  background-color: green;
}
.child2 {
  display: inline-block;
  height: 20px;
  background-color: yellow;
}
复制代码

行内元素垂直对齐的依据:vertical-align 属性

行内元素是如何判断垂直对齐的位置呢?是依据 vertical-align属性。按照 w3school 上的解释:该属性定义行内元素的基线相对于该元素所在行的基线的垂直对齐方式,默认值为 baseline。blog

深刻了解

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

再看一遍 vertical-align 的概念:该属性定义行内元素的基线相对于该元素所在行的基线的垂直对齐方式。这里有两个词组:什么是“行内元素的基线”?什么是“该元素所在行的基线”?图片

毫无疑问,“行内元素的基线”就是咱们在基线中所说的:字母“x”的下端沿。咱们在一个元素里写一个"x",它的下沿就是这个元素的基线。get

能够看到,元素的基线和元素的底线之间是有间距的(上图"x"和红色底边之间),这部分留给"g"、"j"等字母或中文字符

那么什么是“该元素所在行的基线”?一句话归纳就是:所在行的基准元素在对齐时所依据的那条线。咱们把该元素所在行看成父元素,这句话代表,父元素的基线是由它的一个子元素——基准元素决定的,基准元素依据哪条线对齐,父元素的基线就是哪条线

这时咱们就明白了这两个“基线”的区别:

  • 行内元素的基线:是它的自有属性,当该元素没有子元素而只有文字时,取字母"x"的下端沿
  • 行内元素的父元素的基线:来自于它的一个子元素——基准元素,基准元素依据哪条线对齐,父元素的基线就是哪条线

也就是说:若是基准元素采用中线对齐,那么所在行的基线就是基准元素的中线;若是基准元素采用顶线对齐,那么所在行的基线就是基准元素的顶线。

再看垂直对齐的依据与过程

有了上面的铺垫,咱们再回过头来看一下这句话:默认状况下,行内元素的垂直对齐方式为基线对齐。那么,如何根据这句话解释下面的两个元素在垂直方向上的对齐过程呢?

.parent {
  width: 300px;
  height: 100px;
  border: 1px solid blue;
}
.child1 {
  display: inline-block;
  width: 50px;
  height: 100%;
  background-color: green;
}
.child2 {
  display: inline-block;
  width: 50px;
  height: 20px;
  background-color: yellow;
}
复制代码

可能有人会说,这很简单啊,两个元素都没有设置 vertical-align 属性,那么按照默认状况,它们都是基线对齐,因此内部文字就都沿着红线对齐了。

这句话错在哪儿?错在“都是”。正确过程应该是:基准元素按照本身的基线对齐,其他行内元素按照父元素的基线对齐:

  1. 父元素首先肯定基准元素,即最高的元素 —— child1
  2. child1vertical-align 属性默认值为 baseline,所以它对齐本身的基线 —— 做为基准元素,位置并无发生变化,可是会影响父元素的基线位置
  3. 因而父元素的基线就是 child1 的基线
  4. child2vertical-align 属性默认值为 baseline,所以它的垂直对齐方式也是“基线对齐”
  5. 可是最重要的一点是: child2按照父元素的基线对齐,而不是按照本身的基线对齐,即 child2 的基线对齐父元素的基线

彷佛看起来两种解释最后都没啥区别啊?为何必定要这么大费周章地讲一遍对齐过程呢?如今让咱们给 child1 添加 vertical-align: middle,想想,child2的位置在哪儿呢?

咦?给 child1 添加 vertical-align: middlechild2 就自动“垂直居中”了?!但是我没有给 child2 设置 vertical-align: middle啊,这是为何?

按照咱们以前的过程再分析一遍,就简单多了:

  1. 父元素首先肯定基准元素,即最高的元素 —— child1
  2. child1 此次采用 vertical-align: middle 中线对齐 —— 做为基准元素,位置并无发生变化,可是会影响父元素的基线位置
  3. 因而父元素的基线就是 child1 的中线
  4. child2vertical-align 属性默认值为 baseline,所以它的垂直对齐方式也是“基线对齐”
  5. child2 按照父元素的基线对齐,因此就是它的基线要对齐 child1 的中线

那这里咱们又要思考,child2 真的垂直居中了吗?答案是没有。由于咱们说“ child2 的基线对齐的是 child1 的中线”,因此 child2 并无垂直居中,而是在中部靠上一点点的位置。

如今咱们给 child2 添加 vertical-align: middle,会发现它降低了一点点,这时候它就真正的垂直居中了:

咱们再分析一下这个过程:

  1. 前三步都同样:父元素的基线是 child1 的中线
  2. child2vertical-align 属性为 middle,采用中线对齐,因此就是它的中线对齐父元素的基线,又或者,至关于它的中线对齐 child1 的中线

总结

到这时,相信你对于浏览器如何实现垂直对齐,已经有一个较为深刻的理解了。你能够修改 child1child2vertical-align 属性为其余值(suptop、...),看看会发生什么,并试着用以上过程解释一下缘由。

  1. 父元素的基线 === 基准元素的 vertical-align 属性对应的线
  2. 每一个行内元素将本身 vertical-align 属性对应的线对齐到父元素的基线

案例原理

伪元素的插入位置

首先,before 伪元素渲染在父元素的全部子元素以前,after 伪元素插入在父元素的全部子元素以后。也就是说伪元素和子元素是同级的。

原理

回到咱们文章开头所说的案例,原理呼之欲出:利用content: ''; height: 100% 获得一个宽度为 0 的伪元素,即它不会显示出来;高度 100%,因此它最高,是所在行的基准元素;利用 vertical-align: middle 将父元素的基线设置为伪元素的中线,而后其余行内元素采用中线对齐时,天然就是要对齐伪元素的中线了。而伪元素的高度为 100%,因此它的中线就是整个父元素的中线,这就实现了其余行内元素的垂直居中。

我对底层原理的猜测

从编译原理的角度出发,我这样理解上面的过程:

浏览器在解析 CSS 的时候,对于一个行内元素:

  • 若是这个行内元素没有任何子元素,即只有文字或是一张图片,那么它的 vertical-align 属性是一个固有属性
  • 这个行内元素的父元素的基线是一个综合属性,归约而得:它先找到本身全部子元素里最高的那个子元素,而后取它的 vertical-align 属性对应的线做为本身的基线

而后把全部的行内元素,依据 vertical-align 属性,对齐到父元素的基线上。

这也解释了为何设置基准元素的 vertical-align 属性时,基准元素位置不变,由于父元素的基线原本就是根据它的 vertical-align 属性值取的

结束语

以上就是我对 vertical-align 和基线的理解,欢迎各位大佬批评指正。

相关文章
相关标签/搜索