## 自适应的水平垂直居中
旅行商人罗伦斯在马车货台上的麦束堆里,发现沉睡中的少女——自称是丰收之神赫萝的美丽少女,有着狼的耳朵及尾巴。
「虽然奴家长久以来被尊为神,不过,奴家就是奴家,奴家是赫萝。」
相比于水平居中用 margin:auto; 的简便,CSS 没有直接的垂直居中属性,必须通过各种诡异的技巧去实现,确实让人很头疼。以上算是一种实现方式,核心的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <style type="text/css"> .outer { text-align: center; background: #b9f9ff; height: 300px; } .outer:before { content: ''; display: inline-block; height: 100%; vertical-align: middle; } .inner { display: inline-block; width: 300px; vertical-align: middle; background: #fffdc6; } </style>
<div class="outer"> <div class="inner" > <p>水平垂直居中</p> </div> </div>
|
这段代码中,最重要的是 .outer:before 这个伪元素。它起到了连接内外元素以及垂直对齐的作用。
需要明白的是,对一个 div 而言,它的伪元素会放在这个 div 包含的任何内容元素的前面,默认为 inline-block 元素(即“行内元素”或者“内联元素”)。示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <style type="text/css"> .outer { background: #b9f9ff; height: 120px; width: 300px; margin: auto; } .outer:before { content: ':before 伪元素'; border: 1px solid; } </style>
<div class="outer">元素内容</div>
|
执行结果:
元素内容
当元素内容为其它元素,尤其是块级元素时,则有内容的 :before 会在最顶上。
<p>元素块级内容</p>
再强调一遍,:before 其实是一个元素的子元素,永远排在其它实际子元素的前面,比如:
1 2 3 4 5 6 7 8 9 10 11 12
| <style type="text/css"> p { border: 1px solid; } p:before { content: ':before'; background:#fffdc6; color: #f00; } </style>
<p class="special">是特殊的子元素</p>
|
的实际执行效果如下:
是特殊的子元素
可以看到,对于 p 元素添加的 border,连 :before 这段文字也被包含在内。
现在再回头来看原始代码,如果把 :before 的部分修改一下,给 :before 元素加个边框,修改内容,使得识别更简单:
1 2 3 4 5 6 7 8
| .outer:before { content: 'B'; border: 1px solid; display: inline-block; height: 100%; vertical-align: middle; }
|
这样这段代码的原理就非常清楚了。首先,:before 伪元素和内部元素(通过 display:inline-block 设置为行内元素)共同构成了“一行文字”。其次,所有的行内元素都利用 vertical-align:middle 进行了垂直居中对齐。最后,再设置 :before 的高度使得它上下都顶到父元素的边框。这样,同一”行”内的其它元素在视觉就都相对父元素垂直居中了。其实它们在逻辑上真正对齐的对象是 :before。而 :before 自己,则被“卡”到了正中间的位置。
最后,由于 :before 在没有实际内容(通常用 ” ” 空格填充 content 属性)时其实也有宽度,所以在父元素上使用针对文本的 text-align: center; 虽然可以把左右居中也一起做掉。不过还是用常规的 margin:auto 更精确一点。解决办法是对 :after 伪元素也设置 content:” “。
PS:因为 ie6 不支持伪元素,所以……要不还是用 table 吧。