CSS垂直居中

44年前咱们把人送上月球,但在CSS中咱们仍然不能很好实现垂直居中——@James Anderson前端

让一个元素水平居中对于CSS来讲很是简单:若是是一个内联元素,咱们能够在他的父元素上设置text-align:center;;若是是一个块元素,咱们可使用margin:auto;。然而,只要一想到让一个元素垂直居中,让人死的心都有了。浏览器

多年来,垂直居中已成为CSS的不朽神话,也是前端专业人士群体中的一个内部笑话。缘由是:布局

  1. 常常须要使用
  2. 理论上看上去很是简单
  3. 过去实战中要实现是极其困难,特别是元素大小固定时

前端开发人员多年来尽所能的来解决这个问题,共中最使人不安的是使用了不少Hack手段。在这一节中,咱们一块儿探索一些实现垂直居中现代技术。注意,有一些受欢迎的技术,不在这里讨论,主要是由于:flex

  1. 表格布局不讨论(表格显示模式),由于它须要一些冗余的HTML标签
  2. inline-block方法不包括,由于要使用不少Hack手段

然而,若是你对这方面感兴趣,你能够阅读Chris Coyier写的博文《Centering in the Unknown》,里面介绍了这两种技术。.net

若是没有特殊声明,后面示例用的HTML结构都是在<body>元素中插入下面的标签:3d

<main>
    <h1>Am I centered yet?</h1>
    <p>Center me, please!</p>
</main>

为了获得下图所示效果,咱们也应用一些基本的CSS样式,好比background、padding等等:code

绝对定位解决方案

最先实现垂直居中的技术是元素须要一个固定的宽度和高度:orm

main {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -3em; /* 6/2 = 3 */
    margin-left: -9em; /* 18/2 = 9 */
    width: 18em;
    height: 6em;
}

从本质上讲,它将元素的左上角点移到视窗中心点,而后使用负的margin(使用margin-top和margin-left),并且margin的值是元素宽度和高度的一半,使元素的中心点与视窗的中心点重合。若是使用calc()能够减小两个样式:blog

main {
  position: absolute;
  top: calc(50% - 3em);
  left: calc(50% - 9em);
  width: 18em;
  height: 6em;
}

显然,这种方法最大的问题是,元素须要一个固定的尺寸,而须要垂直居中元素的尺寸经常是须要由它的内容来决定。若是咱们有办法使用百分比来控制元素尺寸,咱们的问题就解决了。不幸的是,对于大多数CSS属性(包括margin)百分比的值是相对于其父元素的宽度来决定。开发

在CSS中经常能够看到不少解决方案是难以想象。在这个例中,就可使用CSS3的transform。能够在transform中的translate()使用百分比,让元素移动是相对于自身的宽度和高度,这种方案正是咱们须要的。

main {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

固然,没有哪门技术是完美的,在实际使用中要注意一下如下几个事项:

  1. 绝对定位一般不是一个很好的选择,由于它对总体的布局影响至关的大。
  2. 若是垂直居中元素的内容比视窗高度更高的话,它的顶部会被裁剪掉,以下图所示。可是这个问题能够解决,只不过须要使用一些Hack手段。
  3. 在一些浏览器中,可能会致使元素出现略微的模糊,那是由于元素有可能被放置在半个像素位置上。咱们能够经过transform-style:preserve-3d来解决,尽管这是一个Hack手段,不能保证它不会过期。

视窗单位的解决方案

若是想避免使用绝对定位,咱们仍然可使用translate()方法,其值恰好是元宽度和高度的一半。然而,咱们如何不使用top和left将元素从top和left移动50%的偏移量呢?

首先想到的是给margin属性一个百分数,像这样:

main {
    width: 18em;
    padding: 1em 1.5em;
    margin: 50% auto 0;
    transform: translateY(-50%);
}

然而,正如你所看到的效果,以下图所示:

这产生了很是奇怪的效果。主要缘由是margin的百分比计算是相对于父容器的width来计算。是这样的,甚至包括margin-top和margin-bottom。

值得庆幸的是,若是咱们想让元素在视窗中居中,仍是有但愿的。CSS Values and Units Level 3定义了一种新的单位,称为相对视窗(viewport-relative)长度单位。

  1. vw是相对于视窗的宽度。与你预期恰好相反,1vw至关于视窗宽度的1%,而不是100%
  2. 与vw类似的是,1vh至关于视窗高度的1%
  3. 若是视窗的宽度小于高度,1vmin等于1vw,反之,若是视窗宽度大于高度,1vmin等于1vh
  4. 若是视窗的宽度大于高度,1vmax等于1vw,反之,若是视窗宽度小于高度,1vmax等于1vh

在这个示例中,咱们须要给margin的值设置vh单位:

main {
    width: 18em;
    padding: 1em 1.5em;
    margin: 50vh auto 0;
    transform: translateY(-50%);
}

正如你看到效果很完美。

固然,这种方法有用性是有极限的,由于它只适用于元素在视窗中垂直居中。

请注意,还可使用相对视窗单位来建立全屏效果,并且不须要使用任何脚本。更多细节能够阅读Andrew Ckor写的《Make full screen sections with 1 line of CSS》博文。

Flexbox的解决方案

这无疑是最好的解决方案,因Flexbox的出现就是为了解决这样的问题。其余解决方案仍然可用,惟一缘由是他们能更好的在浏览器上呈现,不过Flexbox在现代浏览器也获得更好的好支持。

只须要两个样式,在须要垂直居中的父元素上设置display:flex(这个示例中就是<body>)和在垂直居中的元素上设置margin:auto(这个示例中就是<main>):

body {
    display: flex;
    min-height: 100vh;
    margin: 0; 
}
main {
    margin: auto;
}

注意,当使用Flexbox和margin:auto时,元素不只水平居中,并且也会垂直居中。也注意,咱们甚至没有设置宽度(若是咱们想要也能够设置),其实指定的宽度至关于max-content。

若是浏览器不支持Flexbox,那么结果看起来就会像下图(若是咱们给元素设置了宽度):

即便不是垂直居中,仍是能够接受的。

Flexbox的另外一个优势是,可让匿名容器垂直居中。例如,咱们将结构换成:

<main>Center me, please!</main>

咱们能够经过align-items和justify-content属性使设置固定尺寸的<main>容器里面的文本居中。以下图所示:

咱们能够在<body>和须要居中的元素<main>使用相同的属性,同时使用margin:auto作为备用,以于优雅降级。

main {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 18em;
    height: 10em;
}

新特性:对齐全部东西

CSS Box Alignment Level 3已经在计划,在将来咱们甚至不须要使用不一样的布局模式就能很是容易的实现垂直居中,咱们只须要像下面这样作:

align-self: center;

无论元素上使用其余样式,这个未来都能运行。这听起来使人难以置信,但未来在浏览器中是能够渲染的。

相关文章
相关标签/搜索