关于 vertical-align 你应该知道的一切

本文首发于政采云前端团队博客: 关于 vertical-align 你应该知道的一切

前言

vertical-align,写过 CSS 的朋友们确定都知道这个属性的做用,顾名思义,垂直对齐,主要目的用于将相邻的文本与元素对齐。MDN 中对它的定义以下:css

一种简单的 CSS 属性,用来指定行内元素(inline)或表格单元格(table-cell)元素的垂直对齐方式。html

咱们对于它的直观定义是与 text-align:center 相相似,一个控制水平方向对齐方式,一个控制垂直方向对齐方式。可是在不少状况下,咱们发现设置属性以后并没生效。接下来让咱们步步深刻学习,共同揭开 vertical-align 的神秘 “面纱” 吧。前端

首先咱们先讲一下,要实现垂直居中,咱们为何选择 vertical-align 这样一个不起眼的 CSS 属性。segmentfault

  • float:只能对齐它们的顶部,并且可能致使布局塌陷,须要手动清除
  • position:absolute:会使元素脱离文档流,以至于它们不能影响周围的元素
  • 手动添加内外边距的方法:须要父元素高度固定
  • transform:translateY:属于 CSS3 新特性,对 IE八、IE9 有一些兼容性的问题

使用 vertical-align 你能在不一样场景下去进行灵活细微的元素对齐工做,而且它有很好的的兼容性,详情以下图所示:浏览器

前置准备

在认识 vertical-align 属性以前,首先要了解几个基本的概念。wordpress

  • 基线:书写英语字母时,字母 X 底部所在的位置,能够了解下 字母’x’在CSS世界中的角色和故事
  • 行高(line-height):两行文字基线之间的距离
  • 内联盒子,更深刻的理解能够参考 CSS盒子模型

  • content area: 围绕文字看不见的 Box,其大小与 font-size 有关
  • inline boxes :不会成块显示,而是并排显示在一行的 boxes ,如 spanaem 等标签以及匿名 inline boxes(即不含把标签的裸露的文字)
  • line boxes:由一个一个的 inline boxes 组成,一行即为一个 line box
  • containing box:外层盒子模型,包含了其余的 boxes
  • 起做用的前提:元素为 inline 水平元素或 table-cell 元素,包括 spanimginputbuttontd 以及经过 display 改变了显示水平为 inline 水平或者 table-cell 的元素。这也意味着,默认状况下,divp 等元素设置 vertical-align 无效

值得注意的是:例如 floatposition: absolute,一旦设置了这两个属性之一,元素的 display 值被忽略,强制当成 block 方式处理,所以,vertical-align 也就失去了做用。布局

vertical-align 属性值

除 Inherit 继承 以外,vertical-align 的属性值能够归为如下 4 类
  • 线类,如 baseline、top、middle、bottom;性能

    • baseline 为 vertical-align 的默认值,其意思是指基线对齐

咱们能够把每个行框盒子的后面想象有一个看不见的节点 x(该节点继承了 line-height ),由于默认对齐方式为基线对齐,因此 ` .text` 就是和这个字母 x 的下边缘对齐。

在实际应用中咱们常常会遇到下图这种状况,你可能会容易的解决这种没法对齐的问题,可是你知道是什么缘由致使他们这个样子吗?

```html
<ul class="box">
  <li>文本</li>  
  <li></li>
</ul>
<style>
  .li {
    font-size: 20px;
    width: 160px;
    height: 160px;
    display: inline-block;
    border: 1px solid #ccc;
  }
</style>
```

![](https://zcy-cdn.oss-cn-shanghai.aliyuncs.com/f2e-assets/8eca4169-7e78-4564-b630-53b5a4c6f244.png?x-oss-process=image/quality,Q_75/format,jpg)

这里就涉及到了 inline-block 基线的定义,inline-block  的基线是正常流中最后一个(行盒子) line box 的基线,可是,若是这个 line box 里面没有 inline boxes 或者其 overflow 属性值不是 visible,那么其基线就是 margin bottom 的边缘。

如上图所示,第一个元素基线是子元素”文本“的基线,而第二个是盒子的底边缘,默认基线对齐,两个元素基线位置不一致,全部会产生上图现象,知道了缘由,咱们只需设置元素的 vertical-align 属性为  top/bottom/middle  就能够轻松对齐了。

* top 与 bottom

    对于内联元素,指的是元素的顶部(底部)和当前行框盒子的顶部(底部)对齐;即与 line-box 的顶部(底部)对齐。

    对于 table-cell 元素,指的是元素的顶 padding 边缘和表格行的顶部对齐。

    基本效果以下图:    

    ![](https://zcy-cdn.oss-cn-shanghai.aliyuncs.com/f2e-assets/9c2e25c1-89b4-474d-aa71-59975c2b69dc.png?x-oss-process=image/quality,Q_75/format,jpg)

* middle 这个属性值用得比较多。

    对于内联元素指的是元素的垂直中心点与行框盒子基线往上 1/2x-height 处对齐,简单点说就是字母 X 的中心位置对齐;对于 table-cell 元素,指的是单元格填充盒子相对于外面的表格行居中对齐。![](https://zcy-cdn.oss-cn-shanghai.aliyuncs.com/f2e-assets/d6271c51-27c7-4906-8de7-e04c04aa0abb.png?x-oss-process=image/quality,Q_75/format,jpg)
  • 文本类学习

    text-top,指的是盒子的顶部和父级内容区域的顶部对齐,即与 content-area 顶部对齐。 text-bottom,指的是盒子的底部和父级内容区域的底部对齐,即与 content-area 底部部对齐。

    例子以下:字体

    <div class="box">
        <span class="f12">12px</span>
        <span class="f16">16px</span>
        <span class="f20">20px</span>
        <img src="./panda.jpg"/>
    </div>
    <style>
      .box {
        font-size: 16px;
      }
      img {
        vertical-align: text-top; 
        width: 100px;
        height: 100px; 
      }
      .f12 {
        font-size: 12px;
      }
      .f16 {
        font-size: 16px;
      }
      .f20 {
        font-size: 20px;
      }
    </style>

    content-area 即围绕文字看不见的 box,其大小与 font-size 有关,能够当作是鼠标选中文字后高亮的背景色区域,上面的例子中,因为父元素字体设置的是 16px ,因此图片的 vertical-align 设置 text-top 的时候,就能够当作是跟子元素为 16px 元素的内容区域顶部对齐,它与 line-height 无关

  • 上标下标类

    如 sub、super;这两个属性用的比较少。
    • super 属性效果至关于 html 标签 <sup></sup> 的效果
    • sub 属性效果 至关于 html 标签 <sub></sub> 的效果
  • 数值百分比类,如 10px、1em、5%

    之因此数值和百分比写在一块儿主要是他们有如下共性:都带数字、都支持负值、行为表现一致
    • vertical-align 支持数值的特性,兼容性也很是好,但大部分开发人员殊不知道 vertical-align 支持数值。对于数值,咱们要知道的是:一、正值表示由基线往上偏移,负值表示由基线往下偏移。二、百分比则是基于 line-height 来计算的

须要注意的是:除了 top 与 bottom 是使元素相对于整行垂直对齐外,其余属性值都是相对于父元素。因此,在开发时,咱们只须要关注当前元素和父级,两元素先后并无直接影响

vertical-align 与 line-height 之间的基友关系

说到 vertical-align 就要讲到它与 line-height 之间密切的关系,从上面咱们都知道百分比类型是根据 line-height 来计算的。但事实是 对于内联元素,vertical-align 与 line-height 虽然看不见,但实际上「处处都是」。其实咱们不少时候发现设置 vertical-align 属性无效,这颇有可能就是 line-height 的缘由了,下面咱们来看两个典型的例子。

  • Demo 1:任意一个块级元素,里面如有图片,则块级元素高度基本上都要比图片的高度高
<div class="box">
 <img  src="./panda.jpg" />
</div>
<style>
.box {
  width: 300px;
  border: 1px solid #ddd;
}
img {
  width: 100px;
  height: 100px;
}
</style>

产生这种现象的缘由:空白节点、line-height vertical-align 属性;图片后放置空白节点 X,会发现图片的基线是元素底部,与“空白节点”的基线对齐,那解决这种问题有如下几个方法:

(1)将图片设置为 display:block (利用 vertical-align 的生效前提)

(2)将 vertical-align 设置为 top,bottom,或者 middle 等值(利用属性值的表现行为)

(3)将 line-height 设置为 0 (利用 line-height 为 0 时,基线上移)

(4)将 font-size 设置为 0 (若是 line-height 的值为相对值)

(5)将 img 设置浮动或者绝对定位 (若是布局容许的话)

  • Demo 2:近似垂直居中
<div class="box">
  <span class="son"></span>
  x
</div>
<style>
.box {
  width: 300px;
  height: 150px;
  line-height: 150px;
  font-size: 20px;
  border: 1px solid #ddd;
  position: relative;
}
//  绘制父元素的垂直中心线
.box::after  {
  content: "";
  position: absolute;
  display: block;
  width: 100%;
  height: 1px;
  background-color: red;
  top:0;
  bottom: 0;
  margin: auto;
  left: 0; 
  }  
.son {
   display: inline-block;
   width: 100px;
   height: 100px;
   vertical-align: middle;
   background-color: purple;
   position: relative;
}
.son::after  {
    content: "";
    position: absolute;
    display: block;
    width: 100%;
    height: 1px;
    background-color: #317ffd;
    top:0;
    bottom: 0;
    margin: auto;
    left: 0;  
  }
</style>

如图所示(为了更明显我使用了色块来标识),当子元素(图片)设置了 vertical-align:middle,并非绝对居中,而只能说是近似居中。子元素的垂直中心线与父级元素基线的位置往上二分之一 X 高度(X 的中心) 所在线对齐,通俗一点讲,就是图中红线表示父元素的垂直中心线,蓝线表示子元素的垂直中心线,能够明显的看到 蓝线 与 X 的中心保持一致,但较红线偏低。若是绝对居中的话,两条线应该彻底重合。

为何会产生这种现象呢?主要缘由在于文字具备下沉特性,从而致使蓝线没法绝对与红线对齐。当文字大小足够小时,咱们能够忽略。从而近似的实现居中效果。可是文字越大,影响就越明显。

那对于这样的问题咱们要怎么解决呢?如下提供几种思路:

一、设置后面的 “空白节点 X ” 的垂直对齐方式也是 vertical-align:middle ,然而,既然称之为 “空白节点” 就表示不会受非继承特性的属性影响,因此,根本无法设置 vertical-align:middle ,除非你本身建立一个显示的内联元素或者伪元素。

二、“空白节点” 能够受具备继承特性的 CSS 属性影响,因而,咱们能够经过其余东西来作调整,让字符的中线和字符内容中心线在一块儿,或者说在一个位置上就能够了。设置父元素 font-size:0 , 所以此时 content area 高度是 0,各类乱七八糟的线都在高度为 0 的这条线上,绝对中心线和中线重合。效果以下:

这种经过 line-height 定高,元素 vertical-align:middle 垂直居中的方法不只适用于现代浏览器,连 IE 浏览器也是支持的,可是这里只有在 IE7 中须要注意的是图片后面须要换行或者空格,经验证这个不是因为标签闭合引发的,可能只是一个 IE7 的 bug 吧。比较幸运的是,如今不少网站的兼容都是基于 IE9,因此能够忽略这个问题啦。

<div><img src="xxx.jpg"><!-- 这里要折行或空格 --></div>

扩展案例

  • 案例1:任意父级高度的垂直居中

    咱们给父级设置 line-height 的值等于 height 的值,实现了近似垂直居中的效果。那若是父级的高度是随着内容的变化而变化的怎么办?此时没法给父级设置一个特定的值,也不能使用百分比,由于 line-height 是根据字体的大小来计算的。

    好比下面这种状况,整个盒子高度是肯定的,可是文本的内容不肯定。同时要求两种表现形式相同,咱们要怎么实现呢?

    <ul>
      <li class="text-container">
        <span>我是单行文本我是单行文本</span>
      </li>
      <li class="text-container">
        <span>我是多行文本我是多行文本我是多行文本我是多行文本我是多行文本我是多行文本</span>
       </li>
     </ul>
    <style>
      .text-container {
        height: 150px;
        text-align: center;
        vertical-align: middle;
      }
      .text-container:after {
        content: "";
        display: inline-block;
        width: 0;
        height: 100%;
        vertical-align: middle;
      }
      span {
        vertical-align: middle;
        display: inline-block;
        max-width: 90%;
        max-height: 100px;
        overflow: hidden;
      }
    </style>

固然实现方式千千万,既然咱们知道了 vertical-align 的原理。为何不学以至用呢?按照以前的讲解,咱们能够借助空白节点,空白节点咱们看不见,可是若是能够给它设置一个高度,让它与父级高度一致,就解决了这个问题。怎么给高度呢?答案是借助伪元素。那么咱们解决这类问题就可使用如下步骤了:

    • 主体元素 inline-block 化
    • 0 宽度 100% 高度的辅助元素(伪元素)
    • vertical-align : middle
    • 案例 2:实现多图列表的两端对齐

      在作相似商品列表的布局时,咱们时常须要每一行列表的实现两端对齐。实现的方法有不少,这里咱们用 display:inline-block + 辅助元素 来实现。

      <dl class="container">
        <dt><img src="./7.jpg"/></dt>
        <dt><img src="./7.jpg"/></dt>
        <dt><img src="./7.jpg"/></dt>
        <dt><img src="./7.jpg"/></dt>
        <dt><i class="justify-fix"></i></dt>
        <dt><i class="justify-fix"></i></dt>
        <dt><i class="justify-fix"></i></dt>
        xxx
      </dl>
      <style>
        .container {
          text-align: justify;
          width: 400px;
          margin: 50px  auto;
          border:  1px solid #ddd;
          line-height: 0;
         }
        dt {
          list-style: none;
          display: inline-block;
          width: 100px;
        }
        .container img {
          width:100px;
          height:100px;
        }
        .justify-fix {
          display: inline-block; 
          width: 100px;
          outline: 1px dashed #317ffd;
          vertical-align: middle;
        }
      </style>

    咱们会一眼就看到在图片周围处处都是空白空隙,那么这些空隙是什么缘由形成的呢?不少时候,复杂问题是由简单问题组合而成的,那么咱们能够按照如下想法来简化问题。

    咱们能够想象整个布局只存在虚线框中的部分。大的部分都是由一块一块的虚线框中部分组合而成的。咱们会惊喜的发现这个现象就是上面所说的任意一个块级元素,里面如有图片,则块级元素高度基本上都要比图片的高度高问题,那么产生的缘由就知道了,是 line-height 与 vertical-align 之间关系产生的影响。

    上面已经讲过如何解决此类问题,咱们直接给父元素 line-height:0 ,这样每一个虚线框中小的空隙就消失了。可是能够明显的看到底部有很大的空隙并无消除。为了更清楚,我把占位 i 元素 outline 高亮下。而且添加一个空白节点 x。

    最后一个 dt 与咱们手动添加的空白节点 X 的基线对齐。还记得前面说过的两个 inline-block 排列错位的例子吗? 这个现象就是由 inline-block 基线问题引发的。正如图中红色框展现的,dt 的基线是元素底部,根据上面所讲的,给占位元素i加一个 vertical-align:bottom/top 属性。而后就完美地解决了~

    总结

    本文讲解了 vertical-align 的基本属性以及各类表现,同时对一些实际应用中 vertical-align 无效现象作了简单的分析阐述,并为解决此类问题提供了思路。本文讲解可能不全面,不成熟,欢迎在评论区留下宝贵评论,共同探讨,共同进步。

    参考文献

    招贤纳士

    政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在平常的业务对接以外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推进并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

    若是你想改变一直被事折腾,但愿开始能折腾事;若是你想改变一直被告诫须要多些想法,却无从破局;若是你想改变你有能力去作成那个结果,却不须要你;若是你想改变你想作成的事须要一个团队去支撑,但没你带人的位置;若是你想改变既定的节奏,将会是“5 年工做时间 3 年工做经验”;若是你想改变原本悟性不错,但老是有那一层窗户纸的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但愿参与到随着业务腾飞的过程,亲手推进一个有着深刻的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我以为咱们该聊聊。任什么时候间,等着你写点什么,发给 ZooTeam@cai-inc.com

    相关文章
    相关标签/搜索