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;

無論元素上使用其餘樣式,這個未來都能運行。這聽起來使人難以置信,但未來在瀏覽器中是能夠渲染的。

相關文章
相關標籤/搜索