另辟蹊径,CSS设置垂直居中

题外话:

一直以来,使用CSS设置内容在容器中的垂直居中,并同时做到多浏览器兼容都是一个困扰前端开发人员的麻烦问题。网上流传的方法中大多兼容性差,或者代码结构复杂,而且通用性差。

内容的垂直居中问题一般会分以下几种情况:

1.固定高度,单行文本垂直居中

2.固定高度,多行文本垂直居中

3.有最小高度,当内容多时高度自适应

以上三种情况,用table设置td的vertical-align可以完全解决,但是设置垂直居中使用table,会造成代码冗余,因此适当用line-height或者position等方法也未尝不可。但是大多情况下,局限性太大,兼容性也有问题。

来看一下下面的的这个设计图。

要如何实现,恐怕就犯难了,以上的方法可能都无法很好的处理。

该图中的需求有几个,每行信息在说明文字少的时候有默认的最小高度,每列要求各个数据水平方向垂直居中对齐。每个位置的数据都有可能是单行或多行,数据完全显示,每行之间有间距。

对以上要求显而易见使用table会很方便,但是如果每行之间的间距的如何处理,可能就会有问题了。

[a]每行一个table呢?

[b]还是整个数据都是一个table,每列是一个tr。

[a]的方法会产生很多冗余的标签,页面结构会很复杂。[b]方法的话,每行之间的间距不能用table处理,兼容性问题无法解决。

如何解决?

对inline-block有过仔细了解的人就可能会知道,inline-block具有inline的一些属性,这里要使用的就是他对 vertical-align: middle的支持,对这个了解的人就很少了。

那么如何实现?

对图中的结构,HTML代码如下:

<div class="list">
    <p style="width:80px;">10% off Economy class</p>
    <p style="width:160px;">Can be modified</p>
    <p style="width:160px;">Can be refunded.</p>
    <p style="width:160px;">Can be endorsed</p>
</div>
<div class="list">
    <p style="width:80px;">first class</p>
    <p style="width:160px;">Free change permitted within same class if available at least 4 days prior to departure.</p>
    <p style="width:160px;">20% of fare charged (minimum CNY50 charge). </p>
    <p style="width:160px;">Can not be endorsed</p>
</div>

上面是理想状态下代码结构,当然你可以为了语义,修改标签。
那么CSS要如何写呢?下面就是我所给出的方法,为了说明问题,请注意粗体部分代码:

body{color:black;background-color:white;padding:50px;}
* {font-size: 12px;font-family:tahoma;margin: 0;padding:0;border-width: 0;}
.list{width:650px;margin-bottom: 1px;padding: 10px;border: solid 1px #00a0da;background-color:#e5f3f8; }
.list p {vertical-align: middle;display: -moz-inline-stack;display: inline-block;zoom:1;*display:inline;padding:0 10px;}

如果你试过上面的代码之后就会注意到两个问题:

[1.]在firefox出现一个问题,当div元素的宽度和他的子元素宽度计算出来一致的时候,最后一个子元素会换行,这个问题在精确布局的时候要注意一下,是由于被转为inline-block的元素在firefox中被认为具有inline性质(想想两个span标签之间换行后,浏览器如何解析),代码换行会被认为是在代码之间生成一个空格,空格造成占位引起的。解决起来很简单,既然换行引起空格占位,不换行就行了。
[2.]inline-block元素之间的垂直居中总会以元素中最高的那个元素为基准做垂直居中对齐。这个问题后面讲。
[1.]的解决方法,让代码紧凑点就可以了,修改HTML代码后:

<div class="list"><p style="width:80px;">10% off Economy class</p><p style="width:160px;">Can be modified</p><p style="width:160px;">Can be refunded.</p><p style="width:160px;">Can be endorsed</p> </div>
<div class="list"><p style="width:80px;">first class</p><p style="width:160px;">Free change permitted within same class if available at least 4 days prior to departure.</p><p style="width:160px;">20% of fare charged (minimum CNY50 charge). </p>
<p style="width:160px;">Can not be endorsed</p></div>

[2.]的情况我们注意到了,我们会利用这一点设置列元素的默认高度。既然inline-block元素之间的垂直居中总会以元素中最高的那个元素为基准做垂直居中对齐,那么默认高度我们可以选取合适的元素去设置高度比如每行最后一个元素,内容固定,给他设置高度就行了,这样默认高度就ok了。当其他位置因为内容过多,造成高度变高,那么基准会变换位最高的元素,仍然实现每行的垂直居中。如果其他位置因为内容过少,基准以最后一个元素的为准,满足默认高度的情况需要。
但是如果以上的最后一个元素也会有内容多少变化的问题,那么这时候你可以创建一个空标签给个高度让它做每行元素的对齐基线。
例如:

<div class="list"><b>hi</b><p style="width:80px;">first class</p><p style="width:160px;">Free changepermitted within same class if available at least 4 days prior to departure.</p><p style=
"width:160px;">20% of fare charged (minimum CNY50 charge). </p><p style="width:160px;">Can not be endorsed</p></div>
———————–style————————
.list b{display: -moz-inline-stack;display: inline-block;zoom:1;*display:inline; vertical-align:middle;height:50px;border:solid 1px #88cd3e;background-color:#ce6;}

添加空元素之后,问题就解决了。
完整代码:

<!DOCTYPE HTML>
      <html>
       <head>
        <meta meta charset="utf-8">
        <title>Demo</title>
        <style type="text/css" media="all">
         body{color:black;background-color:white;padding:50px;font-size: 12px;line-height:16px;font-family:arial; color: #1E346E;}
         * {margin: 0;padding:0;border-width: 0;}
         .list{vertical-align: middle;width:640px;margin-bottom: 1px;border: solid 1px #00a0da;background-color:#F0F5FF; }
         .list:hover{background-color:#d9e7f5;}
         /*----------set vertical align middle----------*/
         .list p,.list b { vertical-align: middle;display: -moz-inline-stack;display:inline-block;zoom:1;*display:inline;}
         .list p { padding:10px;}
         /*----------set min-height----------*/
         .list b { height:52px;width:1px;overflow:hidden;margin-left:-1px;background-color:#009Cd0;}
        </style>
       </head>
       <body>
        <div class="list"><b>&nbsp;</b><p style="width:80px;">first class</p><p style="width:160px;">Can be modified</p><p style="width:160px;">Can be refunded.</p><p style="width:160px;">Can be endorsed</p></div>
        <div class="list"><b>&nbsp;</b><p style="width: 80px;">Economy class</p><p style="width:160px;">Can be modified</p><p style="width:160px;">Can be refunded.</p><p style="width:160px;">Can be endorsed</p></div>
        <div class="list"><b>&nbsp;</b><p style="width:80px;">23% off Economy class</p><p style="width:160px;">One free change permitted within same class if available; further changes charged 10% of fare. Passengers must go to CA ticketing office to process fee-based changes.</p><p style="width:160px;">10% of fare charged. </p><p style="width:160px;">Can not be endorsed</p></div>
        <div class="list"><b>&nbsp;</b><p style="width:80px;">-6% off Economy class</p><p style="width:160px;">Free change permitted within same class if available at least 4 days prior to departure.</p><p style="width:160px;">20% of fare charged (minimum CNY50 charge).</p><p style="width:160px;">Can not be endorsed</p></div>
       </body>
      </html>

如果你不想添加空元素,或者你想到了:before或::before或:after或::after的话,那么问题就解决了一半,这里我们选:after,原因是兼容性略好(为什么?)(IE6,IE7后面解决),样式修改为:

body{color:black;background-color:white;padding:50px;}
* {font-size: 12px;font-family:tahoma;margin: 0;padding:0;border-width: 0;}
.list{width:480px;margin-bottom: 1px;padding: 10px;border: solid 1px #00a0da;background-color:#e5f3f8; }

.list p {vertical-align: middle;display: -moz-inline-stack;display: inline-block;zoom:1;*display:inline;padding:0 10px;}
.list:before{content:”hi”;display: -moz-inline-stack;display: inline-block;zoom:1;*display:inline;vertical-align:middle;height:50px; background-color:#ce6;}

IE6、IE7中不支持伪元素:before,但是IE中使用expression的方法大家应该都知道,这里就要用到这个。expression在IE中是有性能问题的,但是我们还是做一些优化,来减低它对性能的损耗。以下是CSS代码部分:

.baseline{content:”hi”;display: -moz-inline-stack;display: inline-block;zoom:1;*display:inline; vertical-align:middle;background-color:#ce6;height:50px;border:solid 1px #88cd3e;}
.list { *zoom:expression(function(x){x.style.zoom = "1";var _tag=document.createElement(’span’);_tag.innerHTML=’&nbsp;’;
_tag.className=’baseline‘;x.appendChild(_tag);}(this));}

通过expression创建元素,创建的元素通过.baseline进行样式处理,以此作基准。另外说明一点,添加x.style.zoom = “1″;可以让IE6仅执行一次expression,IE7在每次窗口变化时会执行一次,尽量减低IE重复执行引起的性能损耗。

完整代码:

<!DOCTYPE HTML>
      <html>
      <head>
       <meta meta charset="utf-8">
       <title>Demo</title>
       <style type="text/css" media="all">
       body{color:black;background-color:white;padding:50px;font-size: 12px;line-height:16px;font-family:arial; color: #1E346E;}
       * {margin: 0;padding:0;border-width: 0;}
       .list{vertical-align: middle;width:640px;margin-bottom: 1px;border: solid 1px #00a0da;background-color:#F0F5FF; }
       .list:hover{background-color:#d9e7f5;}
       /*----------set vertical align middle----------*/
       .list p { vertical-align: middle;display: -moz-inline-stack;display:inline-block;zoom:1;*display:inline; padding:10px;}
       .list:before{content:”hi”;display: -moz-inline-stack;display: inline-block;zoom:1;*display:inline;vertical-align:middle;height:50px; background-color:#ce6;}
       .baseline{content:"hi";display: -moz-inline-stack;display: inline-block;zoom:1;*display:inline; vertical-align:middle;background-color:#ce6;height:50px;visibility:hidden;margin-left:-2em;}
       .list { *zoom:expression(function(x){x.style.zoom = "1";
       var _tag=document.createElement('span');_tag.innerHTML='&nbsp;';
       _tag.className='baseline';x.appendChild(_tag);}(this));}
       </style>
      </head>
      <body>
       <div class="list"><p style="width:80px;">first class</p><p style="width:160px;">Can be modified</p><p style="width:160px;">Can be refunded.</p><p style="width:160px;">Can be endorsed</p></div>
       <div class="list"><p style="width: 80px;">Economy class</p><p style="width:160px;">Can be modified</p><p style="width:160px;">Can be refunded.</p><p style="width:160px;">Can be endorsed</p></div>
       <div class="list"><p style="width:80px;">23% off Economy class</p><p style="width:160px;">One free change permitted within same class if available; further changes charged 10% of fare. Passengers must go to CA ticketing office to process fee-based changes.</p><p style="width:160px;">10% of fare charged. </p><p style="width:160px;">Can not be endorsed</p></div>
       <div class="list"><p style="width:80px;">-6% off Economy class</p><p style="width:160px;">Free change permitted within same class if available at least 4 days prior to departure.</p><p style="width:160px;">20% of fare charged (minimum CNY50 charge).</p><p style="width:160px;">Can not be endorsed</p></div>
      </body>
       </html>

以上的方法是在对inline-block的研究中发现的,主要是需求变化时适应性好,代码结构也比较简单,扩展性也不错,没什么垃圾代码。实际使用时一般我采用添加一个空标签的方法,虽然多一个标签,但是样式表可以精简很多,如果你对代码有某种癖好,不加空标签也ok,用伪元素+IE expression的方法也可以。使用时仍然需要注意的是虽然这个方法可以处理几乎所有垂直居中问题,但是也需要根据情况适度使用,毕竟浏览器对inline-block的渲染还是略有要求的。

本文引用:http://www.dabaoku.com/jiaocheng/wangye/css/201102248939.shtml

posted @ 2014-03-25 14:42  puexine  阅读(201)  评论(0编辑  收藏  举报