先说一下场景,我们希望一个块级元素在另一个高度不定的容器内垂直居中,或者说让一个DIV在容器内是垂直、水平同时居中,这里提供两个解决方案(实际应该还有一种table布局,但是为了符合W3C标准,我不推荐使用):

假如内部DIV的高度和宽度已知,那么采用负边距布局技术
  • 假如内部DIV高度,宽度不固定,采用inline-block居中布局技术

高度、宽度已知

假设我们的HTML布局结构如下:

<div class="container">
	<div class="inner">Something are here</div>
</div>

且已知有如下CSS定义:

.container { height: 200px; } /* 父容器一般要大于子容器的高度才能看到效果,可以任意设置 */
.inner { width: 100px; height: 100px; } /* 子容器高度、宽度固定 */

让.inner垂直且水平居中的做法是(红色):

.container { 
	height: 200px; 
    position: relative; 
}
.inner { 
    width: 100px; 
    height: 100px; 
    position: absolute; 
    left: 50%; 
    top: 50%; 
    margin:-50px 0 0 -50px; 
}

高度、宽度未知

同样见高度、宽度未知的布局结构,但是我们的.inner的高度、宽度是由内部文字自适应,也就是说,内部的标签或许可能还不是块级元素。

此刻,我们可能仅仅知道.contianer的样式:

.container { height:200px; } //这个值同样也是可以任意变换,只要高度大于子容器。

此时,我们可以使用伪类元素“:before”或者“:after”,那么我们的CSS可以这样写:

.container { 
	height: 200px; 
    text-align: center; 
}

.container: before {
	content:"";
    width:0;
    height: 100%;
}
.container:before,.inner {
	display: inline-block;
    vertical-align: middle;
}

原理是这样的,将一个隐形的inline-block元素作为.inner的兄弟,.inner和:before同时都是inline-block类型(既有内联元素的居中特性,又有block不脱离文档流就设置宽高的特性),此时:before的宽度为零,可以让.inner按照父容器的标准“text-align center”,子元素完美居中?;:before的高度为100%,当两个含内联属性的元素在一起时,会产生奇妙的化学反应——:before与.inner自动垂直居中对齐,就像军训时,同志们自觉按队形向左看齐一样!

IE 6怎么搞?!

其实都这年代了,IOS APP都开始不兼容IOS 6了,IE 6 TM还要想着去兼容的公司,我劝您尽早办好离职手续。

不好意思,说远了,好吧,兼容旧版IE的思路不变,因为老版本IE不兼容伪类元素,拿咱们弄个元素在里面就行了:

<div class="container">
	<div class="inner-brother"> 
	<div class="inner">
    Something are here
	</div>
</div>

修改一下样式,做一下简单的Hack:

.container { 
	height: 200px; 
    text-align: center; 
}

.inner-brother {
	content:"";
    width:0;
    height: 100%;
}
.inner-brother,.inner {
	display: inline-block;
    *display: inline;
    *zoom: 1;
    vertical-align: middle;
}
 

这里.inner-brother是等同于:before的,Hack与IE 6的一些常见BUG问题这里就不再敖述。

还没完,不能被IE 6打断

记得上面有个位置说了“完美居中”后面,我打了一个问号,是的,这里有个很恶心的BUG,一个关于4px的BUG(真正当你动手操作的时候,会发现.inner并没有老老实实居中,而是向右移了4个像素),再次检查一遍代码也不会发现有什么问题。

Something are here.

为了更明显地看到效果,我故意设置了内部的宽度为280px,外层的DIV为300px,我们发现,内部的那个玩意左右留白是不均等的。

这里有比较多的解决方案,比如Hack负边距,也就是内部的DIV向左边距设置-4px,但是我这里有一个更优雅的解决方案:

.container { 
	height: 200px; 
    font-size:0; 
}
.inner {
	font-size: 16px; //自己设置字号大小
}

经测试,该方案在各个浏览器(IE 8+,Chrome,FireFox)下表现良好。

Something are here.

两种居中的用途

针对提及的两种解决方案,个人认为是有不同用途的,前者因为脱离了文档流,推荐在类似弹出自定义的居中对话框的时候使用;而后者,因为属于一种文字流的格式排版,比较“高大上”,建议是在一些复杂苛刻的自适应文字排版中用到。