css元素水平垂直居中的方法

前言

还记得刚开始出来找工作那段时间,有一次去一家公司面试,结果出了个小项目要当场实现,然后是一个移动端登录界面,要求整体位置水平垂直居中,结果当时基础薄弱,根本想不起来怎么实现水平垂直居中,现在想起来都有点自愧不如。

后面虽然回去详细了查看了一些使元素水平垂直居中的方法,也有所收获,但是也没来得及整理一下具体方法。

实现方法

一般来说,根据元素的宽高是否是固定的还是不定的(即随内容不同而改变),适用的方法也有所不同。

固定宽高的元素

方法一:负margin + position + (50%, 50%)

由于元素本身的宽高是固定的,也就是无论其内容怎么改变,widthheight是不变的,因此可以直接『计算』出该元素在其父元素内水平垂直居中的位置:正中心位置(即leftright都为50%的位置)向左上角方向偏移自身宽高的一半。如图所示:

mark

图1

关键就在于使用负margin进行偏移,使元素处于水平居中的位置:

1
2
3
4
5
6
7
8
9
10
.father{
position: relative;
}
.children{
position: absolute;
left: 50%;
top: 50%;
margin-left: -0.5*w; /* w和h就是该元素本身的宽高 */
margin-top: -0.5*h;
}

方法二:margin:auto + position + (0,0,0,0)

这种方法实际上利用了margin:auto这个属性的特点:

1
2
3
4
5
margin:auto的填充规则如下。

(1)如果一侧定值,一侧auto,则auto为剩余空间大小。

(2)如果两侧均是auto,则平分剩余空间。

以上来自张鑫旭大佬的《css世界》—— 4.3.4 深入理解CSS中的margin:auto

可以这么理解:当设置元素的left,right,top,bottom都为0时,代表该元素实际上可以分配的空间大小为父元素的全部大小(即自动填充父元素所有空间),但是该元素又设置了widthheight属性,所以就有所谓的『剩余空间』,利用margin:auto就可以自动平分剩余空间』,使『剩余空间』成为margin

基本css形式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
.father{
position: relative;
}
.children{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: w; /* w和h为固定宽高 */
height: h;
margin: auto;
}

方法三:position + calc

这种方法的原理与方法一是相同的,也是先定位到(50%, 50%)的位置,然后向左上角进行偏移;只不过这里利用了css3calc()方法代替负margin进行偏移:

1
2
3
4
5
6
7
8
.father{
position: relative;
}
.children{
position: absolute;
left: calc(50% - 0.5*w); /* w和h就是该元素本身的宽高 */
top: calc(50% - 0.5*h);
}

可以看出calc()方法中的%是相对于父元素(最近的非static祖先元素?)而言的。

不定宽高的元素

所谓的不定宽高就是指元素的widthheight都没有预先设置,而是随内容不同发生改变(撑开)。既然适用于不定宽高元素的水平垂直居中,那肯定也适用于固定宽高元素。

方法一:flex大法

说句实话,要是css3完全普及并没有兼容性问题的时候,所有的布局几乎都可以使用flex伸缩盒模型来完成,根本不用像之前那么麻烦。利用flex进行水平垂直居中,主要是使用justify-contentalign-items这两个属性,前者是用来控制主轴元素的排列布局方式,而后者就是用来控制侧轴元素的排列布局方式。而flex盒模型中默认的主轴就是水平方向,所以可以用justify-content:center;使元素水平居中,用align-items使元素垂直居中:

1
2
3
4
5
.father{
display: flex;
justify-content: center;
align-items: center;
}

方法二:position + (50%, 50%) + transform

利用css3tansform属性也可以使元素水平垂直居中,其原理和图1一样,先定位到(50%, 50%),然后使用transform属性中的translate()方法进行偏移即可:

1
2
3
4
5
6
7
8
9
.father{
position: relative;
}
.children{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}

没错,transform%是相对于自身的宽高而言的,因此无论宽高多少都可以达到水平垂直居中的效果。

不过使用上面方法的时候,我发现如果该元素没有设置宽度(子元素是文本,宽度由内容撑开),那么该元素的最大宽度只能到父元素的50%(即文本宽度超过50%时会自动换行)。

后话

查了一些文章和资料后,其实还有一些方法可以实现水平垂直居中;如table布局以及line-height+vertical-align+text-align,但是我在尝试line-height方案时,有时会不成功,也不知道原因是啥。

所有的实现效果可以查看:http://php.xiexuefeng.cc/code/css_test/centet_center.html

参考文章

  1. CSS实现水平垂直居中的10种方式(史上最全)
  2. 《css世界》—— 4.3.4 深入理解CSS中的margin:auto