在CSS中的水平居中是很简单的,如果它是一个行内元素,那么对它的父元素使用text-align:center 如果它是一个块级元素,就对它自身使用margin:auto。然而,如果要对一个元素进行垂直居中则令人头皮发麻。
我在《CSS揭秘》中看到了如下几个解决方案:
A. 基于绝对定位的解决方案
main {
position: absolute;
top:50%;
left:50%;
margin-top: -3em;
margin-left: -9em;
width:18em;
height:6em;
}
这段代码先把这个元素的左上角放在了视口的正中心,然后再利用负外边距将自己向上、向左移动自身宽高的一半,从而把元素的中心放在视口的正中心。借助强大的calc()函数,这段代码还可以省略两行:
main {
position: absolute;
top:calc(50%-3em);
left:calc(50%-9em);
width:18em;
height:6em;
}
然而,此方法最大局限是要求元素的宽高固定,这在多数情况下是不适用的。我们希望找到一个属性的百分比值是以自身的宽高为基准的,而非父元素。因此,我们可以使用translate()变形函数来解除对固定宽高的依赖:
main{
position: absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}
当然,这不是十全十美的:
- 使用绝对定位对布局的影响过于强烈
- 如果居中的元素高度上超过了视口,顶部就会被视口裁切掉
B. 基于视口单位的解决方案
假设我们不想使用绝对定位,仍然可以采用translate()技巧来移动元素,但在缺少top和left的情况下如何将元素的左上角放在视口的正中心呢?使用vh!
main{
margin:50vh,auto,0
transform:translateY(-50%);
}
当然,这个技巧的实用性是有限的,因为它只适用于在视口中居中的场景
C. 基于Flexbox的解决方案(最常用、最优雅)
只需两行代码即可,先将待居中元素的父元素设置为flex布局,再给元素自身设置为margin:auto
body{
display:flex;
min-height:100vh;
margin:0;
}
main{
margin:auto;
}
请注意,使用这个方案时,元素将在水平和垂直方向上都被居中。
Flexbox的另一个好处是它还可以将匿名容器即没有被标签包裹的文本节点垂直居中,即:使用align-items:center;justify-content:center;