CSS实现元素水平垂直居中—喜欢对称美,这病没得治


在CSS中对元素进行水平居中是非常简单的:如果它是一个行内元素,就对它的父元素应用text-align:center;如果它是一个块级元素,就对它自身应用margin:auto。然而要对一个元素进行垂直居中,就有点束手无策了,本文介绍了几种常用的垂直居中方法以供参考!

一、表格布局法

利用表格的vertical-align属性,当然首先将显示方式设置为表格,如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">

        .wrap{
            display:table;
            width: 400px;
            height: 200px;
            border: 1px solid red;
        }
        .cell{            
            display:table-cell;
            /*让其内容也水平居中*/
            text-align: center;
            vertical-align:middle;
        }
        .content{
            border: 1px solid green;
        }
    </style>
</head>
<body>
    <div class="wrap">
        <div class="cell">
            <div class="content">
                看,我又居中没?
            </div>
        </div>
    </div>
    
</body>
</html>

这种方法需要在要居中的元素外层再添加一层包裹,如上面的.cell,好处是不用知道需要居中的元素是什么东西,比如上面的.content标签,在css中未对其位置进行任何设置。

二、基于行内块的解决方案(来自于第二篇参考文献)

这种方法确实讲究技巧,在实际实施中估计也不常用,但还是有必要介绍一下。具体思路是在包裹元素内设置一个“ghost”元素,使其高度为包裹元素的100%,然后同时设置“ghost”元素和居中元素的dispaly属性为inline-block,同时vertical-align:middle.这个"ghost"元素可以是一个空的标签,更好的方法是使用::before或者::after伪元素来代替.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        .wrap{
            width: 400px;
            height: 200px;
            border: 1px solid red;
            text-align: center;
        }
        .wrap:before{
            content: '';
            display: inline-block;
            height: 100%;
            vertical-align: middle;
        }
        .content{
            display: inline-block;
            vertical-align: middle;
            width: 150px;
            height: 50px;
            border: 1px solid green;
        }
    </style>
</head>
<body>
    <div class="wrap">
        <div class="content">
            看,我居中没?
        </div>    
    </div>    
</body>
</html>

三、基于绝对定位的解决方案

1.绝对定位+负的外边距
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        .wrap{
            position: relative;
            width: 400px;
            height: 200px;
            border: 1px solid red;
        }
        .content{
            position: absolute;
            top: 50%;
            left: 50%;
            width: 100px;
            height: 50px;
            margin-top: -25px;
            margin-left: -50px;
            border: 1px solid green;
        }

    </style>
</head>
<body>
    <div class="wrap">
        <div class="content">
            看,我居中没?
        </div>    
    </div>    
</body>
</html>

使用这种方法要求居中的元素具有固定的宽度和高度。

上面的方法本质上做了这样几件事情:先把要居中的元素的左上角放在已定位祖先元素的正中心,然后再利用负外边距把它向左、向上移动(移动距离相当于自身宽高的一半),从而把元素的正中心放置在祖先元素的正中心。借助CSS3中强大的calc()函数(当然实际实施过程中要考虑浏览器的兼容性),.content的样式还可以设置成:

<style type="text/css">
        .wrap{
            position: relative;
            width: 400px;
            height: 200px;
            border: 1px solid red;
        }
        .content{
            position: absolute;
            top: calc(50% - 25px);
            left: calc(50% - 50px);
            width: 100px;
            height: 50px;
            border: 1px solid green;
        }

    </style>

注意:表达式中有“+”和“-”时,其前后必须要有空格,如"widht: calc(12%+5em)"这种没有空格的写法是错误的calc函数的具体用法可以参考:
CSS3的calc()使用

2.绝对定位+margin:auto

实现原理:利用css定位规则,设置左右、上下方向定位为0,margin为auto,让css根据定位计算margin值,用hack的方式实现居中。居中块的尺寸需要固定。

寸需要可控

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        .wrap{
            position: relative;
            width: 400px;
            height: 200px;
            border: 1px solid red;
        }
        .content{
            position: absolute;
            width: 150px;
            height: 50px;
            margin: auto;
            top:0;left: 0;bottom: 0;right: 0;
            border: 1px solid green;        
        }

    </style>
</head>
<body>
    <div class="wrap">
        <div class="content">
            看,我居中没?
        </div>    
    </div>    
</body>
</html>

上面提到的两种绝对定位的方案最大的局限就是它要求元素的宽度和高度固定。下面介绍的第三种基于绝对定位的方案则不会出现这个问题,对于需要居中的元素宽高是否固定没有硬性要求,这样居中元素的尺寸就由其内容确定了。

3.绝对定位+transform反向偏移

还是上面的例子将内部元素的设置负的外边距的那两句改成

<style type="text/css">
        .wrap{
            position: relative;
            width: 400px;
            height: 200px;
            border: 1px solid red;
        }
        .content{
            position: absolute;
            top: 50%;
            left:50% ;
            border: 1px solid green;
            transform: translate(-50%,-50%);
        }

    </style>

使用这种方法对于居中元素宽高没有要求的原因是在translate()变形函数中使用百分比时,是以这个元素本身的宽度和高度为基准进行换算和移动的。

当然了,使用基于绝对定位的方法一定要先知道你要居中的对象是哪一个,这样才能对其设置绝对定位,这是与表格布局法明显不同的地方。

四、基于视口单位的解决方案(仅适用于基于视口的居中)

假如不想使用绝对定位,仍然可以采用translate()技巧来让元素以其自身宽高一半进行偏移,但是如果使用绝对定位,也就无法使用left和top使元素左上角位于容器正中心。
我们的第一反应很可能是用margin属性的百分比来实现。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">    
        .content{
            border: 1px solid green;
            margin: 50% auto 0;
            transform: translateY(-50%);
        }
    </style>
</head>
<body>
    <div class="content">
        看,我居中没?
    </div>    
</body>
</html>

实际上的结果却如上图所示,元素到了视口的下方。原因在于margin的百分比是以父元素的宽度作为基准的。在《CSS揭秘》这本大作中提到了一种方法可以正确使元素基于视口居中,该方法采用视口单位vh作为长度单位。1vh表示视口单位的1%。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">    
        .content{
            border: 1px solid green;
            width: 150px;
            margin: 50vh auto 0;
            transform: translateY(-50%);
        }
    </style>
</head>
<body>
    <div class="content">
        看,我居中没?
    </div>    
</body>
</html>

五、基于使用css3弹性布局(Flexbox)的解决方案

css3的伸缩盒布局简直是一切布局的救星,遗憾的是,很多老浏览器不支持,哎哎哎哎!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        .wrap{
            display: flex;
            width: 400px;
            height: 200px;
            border: 1px solid red;
        }
        .content{
            margin: auto;
            border: 1px solid green;
            
        }
    </style>
</head>
<body>
    <div class="wrap">
        <div class="content">
            看,我居中没?
        </div>    
    </div>    
</body>
</html>

想让.content居中就是这么简单,使包裹元素display: flex;要居中的元素margin: auto;这样水平和垂直方向都居中了,而且对于居中元素的宽高也没有要求。

Flexbox还有另一个好处在于,它可以在不知道需要居中的元素是什么的情况下使居中元素居中,就像方法一的效果一样,具体实现是借助:align-items和justify-content仍然用上面的例子.

<style type="text/css">
        .wrap{
            display: flex;
            align-items: center;
            justify-content: center;
            width: 400px;
            height: 200px;
            border: 1px solid red;
        }
        .content{
            border: 1px solid green;        
        }
    </style>

实现效果相同。

六、单行文本时的居中

可以利用line-height属性与元素高度相同

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css">
        .content{        
            width: 150px;
            height: 100px;
            line-height: 100px;
            text-align: center;
            border: 1px solid green;        
        }

    </style>
</head>
<body>    
    <div class="content">
        看,我居中没?
    </div>    
</body>
</html>

六、多行文本的居中

如何实现父容器高度固定,文字可能一行,两行或更多行的垂直居中对齐呢?
可以用一个span标签将所有的文字封装起来,设置文字与图片相同的display属性(inline-block属性),然后用处理图片垂直居中的方式处理文字的垂直居中即可。
核心css代码如下,

//外部div标签:
div{display:table-cell; width:550px; height:1.14em; padding:0 0.1em; border:4px solid #beceeb; color:#069; font-size:10em; vertical-align:middle;}

//内部span标签:
span{display:inline-block; font-size:0.1em; vertical-align:middle;}

添加于2016-8-28

centering-css-complete-guide-偶然发现一个很完整的CSS居中的指南
howtocenterincss-在线生成CSS居中的方案
大小不固定的图片、多行文字的水平垂直居中

参考:
CSS揭秘(英文原版:CSS Secrets)
Centering in the Unknown

posted @ 2016-07-31 20:14  FeMiner  阅读(1562)  评论(0编辑  收藏  举报