zoukankan      html  css  js  c++  java
  • 深入理解css中vertical-align属性

    一、为什么要写这篇文章

    今天看到一个问题:

    两个div 都设置 display:inline-block,正常显示;但是在第二个div中加一个块级元素或者内联元素,显示就变了个样,为什么?

    <meta charset="utf-8"/>
    <style>
    div{
        width: 100px;
        height: 100px;
        border:1px solid red;
        display: inline-block;
    }
    .align{
    /*    vertical-align: top;*/
    }
    </style>
    <body>
        <div>
        </div>
        <div class="align">为什么?</div>
    </body>

    解决方案就是给第二个div加上:vertical-align:top。

    关于vertical-align和基线我知道一点,但是这个问题我没能答出,所以学习总结分享一下。

    二、vertical-align干什么的?

    w3c有一段相关信息如下:

    'vertical-align'
    Value:      baseline | sub | super | top | text-top | middle | bottom | text-bottom | <percentage> | <length> | inherit
    Initial:      baseline
    Applies to:      inline-level and 'table-cell' elements
    Inherited:      no
    Percentages:      refer to the 'line-height' of the element itself
    Media:      visual
    Computed value:      for <percentage> and <length> the absolute length, otherwise as specified

    可以看到vertical-align影响inline-level元素和table-cell元素垂直方向上的布局。根据MDN描述,vertical-align对::first-letter和::first-line同样适用。

    适用于:

    inline水平的元素

    • inline:<img>,<span>,<strong>,<em>,未知元素
    • inline-block:<input>(IE8+),<button><IE8+>....

    'table-cell'元素

    • table-cell:<td>

    所以默认情况下,图片,按钮,文字和单元格都可以用vertical-align属性。

    取值:

    vertical-align: baseline|length|percentage|sub|super|top|middle|bottom|text-top|text-bottom|initial|inherit;

    三、baseline

    1、字母‘x’与baseline

     字母x的下边缘(线)就是基线。不是字母s之类下面有尾巴的字母

    基线甚至衍生出了:

    1. “alphabetic” baseline: “字母”基线 – 英文
    2. “hanging” baseline: “悬挂”基线 – 印度文
    3. “ideographic” baseline: “表意”基线 – 中文

    2、baseline的确定规则


    1、inline-table元素的baseline是它的table第一行的baseline。

    2、父元素【line box】的baseline是最后一个inline box 的baseline。 

    3、inline-block元素的baseline确定规则

    • 规则1:inline-block元素,如果内部有line box,则inline-block元素的baseline就是最后一个作为内容存在的元素[inline box]的baseline,而这个元素的baseline的确定就要根据它自身来定了。
    • 规则2:inline-block元素,如果其内部没有line box或它的overflow属性不是visible,那么baseline将是这个inline-block元素的底margin边界。

    3、例子:inline-block例子

    上图描述:

    上图中从左到右都是line-block元素,红线代表margin-box的边界,蓝线代表baseline;黄色为border,绿色为padding,蓝色为content。

    左边元素包含着没有脱离正常流的内容c,中间元素除了没有脱离正常流的内容c外还增加了overflow:hidden,右边元素没有内容,但是内容区有宽高

    分析图中各种情况inline-block元素的baseline

    上图左图,inline-block元素有处于正常流的内容,根据规则1,所以inline-block的baseline就是最后一个作为内容存在的元素的baseline,也就是内容c的baseline,而c的baseline根据自身定,就是图中蓝色。

    上图中图,inline-block元素overflow:hidden不为visible,根据规则2,该inline-block元素baseline就是inline-block元素的margin-box的下边界了,即图中蓝线。

    上图右图,inline-block元素没有内容,根据规则2,所以其baseline为margin-box的下边界,即蓝线。

    4、例子:baseline确定规则例子 

    举例:

    <style type="text/css">
        .ctn-block{
            display: block;
            background-color: #bbb;
            line-height: 200px;
            font-size: 50px;
        }
        .ctn-block .child1{
            display: inline-block;
            width: 100px;
            height: 100px;
            margin:10px 0;
            vertical-align: baseline;
            background-color: aliceblue;
        }
    </style>
    
    <div class="ctn-block">
        <div class="child1"></div>
        <span>Gg</span>
    </div>
    View Code

     

    分析:

    父元素.ctn-block的base-line是Gg的baseline,

    inline-block元素因为没有内部line box,也没有设置overflow:visible,所以其baseline是底margin边界。

    四、vertical-align基于baseline的不同取值

    1、baseline

    将子元素盒子的baseline与父盒子的baseline对齐。

    2、middle

    将元素盒子的垂直中点与父盒子的baseline加上父盒子的x-height的一半位置对齐

    这里元素盒子的垂直中点容易确定,父盒子的baseline也好确定,但是x-height要进行计算得到,这个x-height就是字母x的高度。

    3、text-top

    将盒子的顶端(margin-top边界)与父盒子的文本区域顶端对齐

    审查盒子看到margin-top的顶端。

    审查文本,看到蓝色区域的上边界就是文本区域顶端。

    最终效果就是盒子的顶端与父盒子文本区域顶端对齐。

    4、text-bottom

    将盒子的底端(margin-bottom边界) 与父盒子的文本区域底端对齐

    和text-top类似,不过将子元素的margin-bottom和文本区域的下边界对齐。

    5、sub

    将子元素盒子的baseline降低,到适当的父盒子的下标位置

    子元素的baseline已经确定了,就是margin-bottom下边界,但是父盒子的下标位置太不好理解。。。首先需要了解下标这个概念,我们可以通过<sub>标签为文字添加下标,将<span>中的内容修改为Gg<sub>Gg</sub>,就会有如下效果。

    这里就是将元素的margin-bottom下边界和下标的baseline对齐。

    6、super

    将元素盒子的baseline升高,到适当的父盒子的上标位置。

    与sub对应,super提升到上标内容的baseline处,首先通过<sup>标签创建上标。

     

    7、percentage

    百分比:升高(正值)或降低(负值)子元素盒子,具体的升高/降低数值由父盒子的line-height的值乘以百分比计算得出。如果百分比为0%,就和vertical-align:baseline一样。

    这个是相当好理解的,就相当于子元素盒子的baseline升高或降低,具体数值为百分比乘以父盒子的line-height。

    本例中,父盒子的line-height为200px,所以设定25%,元素应该上移50px。

    并不是很直观,给它加上一个transform: translate(0, 50px);【相对下移50px】,它又移到那个熟悉的位置了。

     

    8、length

    升高(正值)或降低(负值)子元素盒子。值为升高/降低的距离,如果为0,和vertical-align:baseline一样。

    以我们最常用的px作为单位,设定vertical-align:50px,效果就和上面百分比为25%(200px*25%=50px)一样了,不做例子了。

    五、vertical-align基于line box的不同取值

    当vertical-align设置为top和bottom时,其就不是按照baseline进行定位了,而是根据line box进行定位。子元素盒子的顶部和底部也就是其上下margin外边界。

    1、top

    将子元素盒子的顶部和其所在的line box顶部对齐

    由于vertical-align:top将会让子元素盒子顶部与line box顶部对齐,而如果line box高度小于子元素高度,line box将会被撑开。我们先用一个高度较高的元素撑开line box,然后看看效果:

     

    可以看到,big子元素撑开了line box,而child1的margin-top外边界紧贴在line box的顶端。

    2、bottom

    将子元素盒子的底部和其所在的line box底部对齐

    和top类似,由于big用于撑开line box,可以不必修改其vertical-align的值,仅修改child1为vertical-align:bottom,效果:

    六、inline元素下方可能会有一点空隙

    例子:尝试将li元素在垂直方向上进行对齐的话,这个现象非常常见

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <style type="text/css">
            ul{
                background-color: bisque;
            }
            .box { display: inline-block;
                width: 100px;
                height: 100px;
                background-color: aliceblue;
                /*     vertical-align: middle;*/
            }
        </style>
    
    </head>
    <body>
    
    <ul>
        <li class="box"></li>
        <li class="box"></li>
        <li class="box"></li>
    </ul>
    </body>
    </html>

    1、垂直空隙

    因为li元素默认vertical-align:baseline,而baseline的下方会给字母的一部分留出空间,因此会产生一个空隙,要产生理想的效果,解决方案就是改变line box的baseline位置,比如将这些li设置为vertical-align:middle。【tip:加一个x效果更明显】

    2、水平空隙

    li元素的水平空隙是因为换行引起的,这个换行会变成一个空白,这个空白会被解析为DOM中的文本节点。比如像下面酱紫的代码。

    <ul>
      <li class="box"></li><li class="box"></li>
      <li class="box"></li>
    </ul>

    效果如下:因为前2个li之间没有空白,而2和3个li之间有空白。

    但是上面的代码可读性太差,也不美观,一般这样写

        <ul>
            <li class="box"></li><!-- 注释去空格
         --><li class="box"></li>
            <li class="box"></li>
        </ul>

    我们用一个注释节点代替空白(文本节点),而注释节点渲染的时候是不渲染的。了解更多DOM中的节点类型,可看我的另一篇文章《DOM》

    七、vertical-align:middle让元素下移而不居中的问题分析

    1、问题

    现在有三个inline-box块,高度分别为100px,200px,300px,想让高度为100px的块垂直居中,于是写出了如下代码:

    <style type="text/css">
        .ctn-block{
            background-color: #bbb;
        }
        .ctn-block .child {
        display: inline-block;
        width: 100px;
        background-color: aliceblue;
    }
    .ctn-block .child-1 {
        height: 100px;
    /*    vertical-align: middle;*/
    }
    .ctn-block .child-2 {
        height: 200px;
    }
    .ctn-block .child-3 {
        height: 300px;
    }
    </style>
    ----------------------------------------------
    <div class="ctn-block">
        <div class="child child-1"></div>
         <div class="child child-2"></div>
        <div class="child child-3"></div>
    </div>
    View Code

    给中间div加上vertical-align:middle,效果变为上图二的样子——child-1元素下移了,但是却没有居中。

    2、原因

    从上面可以指定,vertical-align:middle的定位方式是:将子元素盒子的垂直中点与父盒子的baseline加上父盒子的x-height的一半位置对齐。

    子元素盒子的中点很好算,而父盒子的baseline加上父盒子的x-height一半位置又是什么呢?

    首先计算父盒子的baseline:三个子元素的baseline走在一条直线上,就是child-2和child-3的底部。

    然后加上父盒子的x-height:由于chrome下默认font-size是16px,而font-family:sans-serif,所以x-height的一半大概是3-4px,综上,按照如下方式对齐:

    3、 解决方案

     一种方式是将最高的元素设为vertical-align:middle。

    然后将想要居中的也设定为vertical-align:middle,其他的根据需要设定vertical-align:top/bottom。

    原理有点抽象:

    首先明确一点:最高元素设定为vertical-align:middle后,这个元素对于line box来说,baseline就是其中线。

    其他元素设置vertical-align:top/bottom后,它们不影响line box的baseline,所以再将需要设定垂直居中的元素也设定为vertical-align:middle,它们的baseline必然在最高元素的baseline之上,所以会会被强制下移,进行居中。

    .ctn-block .child-1 {
            height: 100px;
            vertical-align: middle;
        }
        .ctn-block .child-2 {
            height: 200px;
            vertical-align:top;
        }
        .ctn-block .child-3 {
            height: 300px;
            vertical-align: middle;
        }

    4、衍生的一种可行的垂直居中方案

    为父元素设定一个伪元素::after,其高度为父元素的高度,display:inline-block,将其设定为vertical-align:middle即可撑开line box,同时line box的baseline为父元素高度一半的位置。然后设定子元素vertical-align:middle,即可实现居中。

    考虑兼容性的话,这里需要使用一些hack,由于IE8不支持::after伪元素,所以需要一个span来替代。而display:inline-block亦需要hack。

    我的《未知宽高图片垂直居中》一文中就用到这种方案。 

    八、其他应用

    ico和文字对齐 

    <style type="text/css">
        .pop-viphead-nologinbox {
            width:500px;
        }
    
        .pop-viphead-nologin-icon {
            display:inline-block;
            width: 14px;
            height: 14px;
            background: url("images/not_login_tip_ico.png") no-repeat;
        }
    
        .pop-viphead-nologin-txt {
            display: inline-block;
            color: #333;
            font-size: 12px;
            margin-left:2px;
        }
    
        .pop-viphead-nologin-btn {
            display: inline-block;
            margin-left: 3px;
        }
    
        .pop-viphead-nologin-btn a {
            display: block;
            width: 76px;
            height: 25px;
            line-height: 25px;
            color: #fff;
            text-align: center;
            background-color: #00adee;
            border-radius: 1px;
            font-size: 12px;
        }
    </style>
    
    <div class="pop-viphead-nologinbox">
        <div class="pop-viphead-nologin-icon"></div>
        <span class="pop-viphead-nologin-txt">您还没有登录哦!</span>
    
        <div class="pop-viphead-nologin-btn"><a href="javascript:;" j-delegate="login">立即登录</a></div>
    
    </div>
    View Code

    我想让左边ico和文字,按钮都对齐。

    .pop-viphead-nologin-icon,.pop-viphead-nologin-txt,.pop-viphead-nologin-btn{
            vertical-align: middle;
        }

    参考资源:

    baseline:

    如果想要了解更多关于baseline的详细的信息,可以参照W3C标准css-inline的baseline部分

    更多关于baseline的确定方式可以参照W3C标准css-align的baseline-rules部分

    vertical-align:

    天镶大神

    垂直居中之vertical-align详解CSS布局之vertical-align

    MDN vertical-align

    [翻译]关于Vertical-Align你需要知道的事情

    w3c line-height和vertical-align

    这篇文章在草稿箱呆了快2年了,重新整理了一下,发布出来。

    本文作者starof,因知识本身在变化,作者也在不断学习成长,文章内容也不定时更新,为避免误导读者,方便追根溯源,请诸位转载注明出处:http://www.cnblogs.com/starof/p/4512284.html有问题欢迎与我讨论,共同进步。

  • 相关阅读:
    SLAM+语音机器人DIY系列:(六)SLAM建图与自主避障导航——4.多目标点导航及任务调度
    SLAM+语音机器人DIY系列:(六)SLAM建图与自主避障导航——3.ros-navigation机器人自主避障导航
    SLAM+语音机器人DIY系列:(六)SLAM建图与自主避障导航——2.google-cartographer机器人SLAM建图
    SLAM+语音机器人DIY系列:(六)SLAM建图与自主避障导航——1.在机器人上使用传感器
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——7.开机自启动ROS节点
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——6.树莓派USB与tty串口号绑定
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——5.Android手机端与robot端ROS网络通信
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——4.PC端与robot端ROS网络通信
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——3.装机后一些实用软件安装和系统设置
    SLAM+语音机器人DIY系列:(五)树莓派3开发环境搭建——2.安装ros-kinetic
  • 原文地址:https://www.cnblogs.com/starof/p/4512284.html
Copyright © 2011-2022 走看看