Flexbox完美解決CSS垂直居中

44年前我們就把人類送上月球了,但現(xiàn)在我們?nèi)匀粺o法在CSS中實現(xiàn)垂直居中。

在CSS中對元素進行水平居中是非常簡單的:如果它是一個行內(nèi)元素,就對它的父元素應用 text-align: center ;如果它是一個塊級元素,就對它自身應用 margin: auto。然而如果要對一個元素進行垂直居中,可能光是想想就令人頭皮發(fā)麻了。

多年以來,垂直居中已經(jīng)成為了CSS領域的圣杯,它同樣也是前端開發(fā)圈內(nèi)廣為流傳的笑話。原因在于它同時具備以下幾條特征:

  • 它是極其常見的需求。
  • 從理論上來看,它似乎極其簡單。
  • 在實踐中,它往往難如登天,當涉及尺寸不固定的元素時尤其如此。

在本篇攻略中,我們將探索現(xiàn)代CSS的強大威力,以全新的思路去攻克各種場景下的垂直居中難題。請注意,有幾種技巧十分流行,但在這里并不會深入探討,原因如下:

  • 表格布局法(利用表格的顯示模式)需要用到一些冗余的HTML元素,因此這里不多介紹。
  • 行內(nèi)塊法也不作討論,因為在我看來這種方法hack的味道很濃。

如果你有興趣,可以去看看Chris Coyier寫的《不為人知的居中方法》。這篇出色的文章詳細講述了這兩種技巧。

代碼初始化


我們基于如下這段HTML代碼,將 <main> 元素在 <body> 元素中垂直居中(實際上我們將要探索的這些技巧是與容器無關(guān)的):

<body>
    <main>這是要居中的元素</main>
</body>

基本樣式信息如下:

body {
  margin: 0;
  padding: 0;
  background: #4AC291;
  font-size: 100% / 1.5 sans-serif;
}
main {
  background: #655;
  color: white;
  text-align: center;
  line-height: 2em;
}
我們的起點

基于絕對定位的解決方案

我們來看一個早期的垂直居中方法,它要求元素具有固定的寬度和高度:

main {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12em;
  height: 2em;
  margin-top: -1em;  /* 2/1 = 1 */
  margin-left: -6em; /* 12/2 = 6 */
}
固定寬高的樣式效果

這段代碼在本質(zhì)上做了這樣幾件事情:先把這個元素的左上角放置在視口(或最近的、具有定位屬性的祖先元素)的正中心,然后再利用負外邊距把它向左、向上移動(移動距離相當于它自身寬高的一半),從而把元素的正中心放置在視口的正中心。借助強大的 calc() 函數(shù),這段代碼還可以省掉兩行聲明:

main {
  position: absolute;
  width: 12em;
  height: 2em;
  top: calc(50% - 1em);
  left: calc(50% - 6em);
}

顯然,這個方法最大的局限在于它要求元素的寬高是固定的。在通常情況下,對那些需要居中的元素來說,其尺寸往往是由其內(nèi)容來決定的。如果能找到一個屬性的百分比值以元素自身的寬高作為解析基準,那我們的難題就迎刃而解了!遺憾的是,對于絕大多數(shù)CSS屬性(包括 margin)來說,百分比都是以其父元素的尺寸為基準進行解析的。

CSS領域有一個很常見的現(xiàn)象,真正的解決方案往往來自于我們最意想不到的地方。在這個例子中,答案來自于CSS變形屬性。當我們在 translate() 變形函數(shù)中使用百分比值時,是以這個元素自身的寬度和高度為基準進行換算和移動的,而這正是我們所需要的。接下來,只要換用基于百分比的CSS變形來對元素進行偏移,就不需要在偏移量中把元素的尺寸寫死了。這樣我們就可以徹底解除對固定尺寸的依賴。

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

這個元素已經(jīng)完美居中了,完全滿足我們的期望。當然沒有任何技巧是十全十美的,上面這個方法也有一些需要注意的地方:

  • 我們有時不能選用絕對定位,因為它對整個布局的影響太過強烈。
  • 如果需要居中的元素已經(jīng)在高度上超過了視口,那么它的頂部會被視口裁剪掉。有一些辦法可以繞過這個問題,但hack味道過濃。
  • 在某些瀏覽器中,這個方法可能會導致元素的顯示有一些模糊,因為元素可能被放置在半個像素上。這個問題可以用 transform-style: preserve-3d 來修復,不過這個修復手段也可以認為是一個hack,而且很難保證它在未來不會出問題。
當需要居中的元素在高度上超過了視口,它的頂部會被裁掉

基于視口單位的解決方案


假設我們不想使用絕對定位,仍然可以采用translate()技巧來把這個元素以其自身寬高的一半為距離進行移動;但是在缺少left和top的情況下,如何把這個元素的左上角放置的容器的正中心呢?

我們的第一反應很可能是用margin屬性的百分比值來實現(xiàn),就像這樣:

main {
  width: 12em;
  margin: 50% auto 0;
  transform: translateY(-50%);
}

產(chǎn)生的效果如下:

基于margin屬性百分比值的樣式效果

這段代碼產(chǎn)生的效果十分離譜。原因在于margin的百分比值時以父元素的寬度作為解析基準的。沒錯,即使對于margin-topmargin-bottom來說也是這樣!

不過幸運的是,如果只是想把元素相對于視口進行居中,仍然是有希望的。CSS值與單位(第三版)定義了一套新的單位,稱為視口相關(guān)的長度單位。

  • vw 是與視口寬度相關(guān)的。與常人的直覺不符的是,1vw 實際上表示視口寬度的 1%,而不是 100%。
  • 與 vw 類似,1vh 表示視口高度的 1%。
  • 當視口寬度小于高度時,1vmin 等于 1vw,否則等于 1vh。
  • 當視口寬度大于高度時,1vmax 等于 1vw,否則等于 1vh。

在我們這個例子中,適用于外邊距的是vh單位:

main {
  width: 12em;
  margin: 50vh auto 0;
  transform: translateY(-50%);
}

在下圖中我們可以看到,其效果堪稱完美。當然,這個技巧的實用性是相當有限的,因為它只適用于在視口中居中的場景。

基于視口相關(guān)的長度單位的樣式效果

基于Flexbox的解決方案


這是毋庸置疑的最佳解決方案,因為Flexbox(伸縮盒)是專門針對這類需求所設計的。我們之所以要討論其他方案,僅僅是因為那些方案在瀏覽器的支持程度上稍微好一些而已。其實目前現(xiàn)代瀏覽器對 Flexbox 的支持度已經(jīng)相當不錯了。

我們只需寫兩行聲明即可:先給這個待居中元素的父元素設置 display: flex(在這個例子中是<body>元素),再給這個元素自身設置我們再熟悉不過的margin: auto(在這個例子中是<main>元素):

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

main {
  margin: auto;
}

請注意,當我們使用Flexbox時,margin: auto不僅在水平方向上將元素居中,垂直方向上也是如此。還有一點,我們甚至不需要指定任何寬度(當然,如果需要的話,也是可以指定的):這個居中元素分配到的寬度等于 max-content。

如果瀏覽器不支持Flexbox,頁面渲染結(jié)果看起來就跟我們的起點圖是一樣的了(如果設置了寬度的話)。雖然沒有垂直居中效果,但也是完全可以接受的。

Flexbo 的另一個好處在于,它還可以將匿名容器(即沒有被標簽包裹的文本節(jié)點)垂直居中。

我們先給這個<main>元素指定一個固定的尺寸,然后借助Flexbox 規(guī)范所引入的align-itemsjustify-content屬性,我們可以讓它內(nèi)部的文本也實現(xiàn)居中(我們可以對<body>使用相同的屬性來使<main>元素居中,但margin: auto方法要更加優(yōu)雅一些,并且同時起到了回退的作用)。

main {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 12em;
  height: 8em;
}
用Flexbox把匿名文本框居中

參考資料


《CSS揭秘》,Lea Verou

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 14,131評論 1 92
  • 1.絕對定位居中技術(shù) 我們一直用margin:auto實現(xiàn)水平居中,而一直認為margin:auto不能實現(xiàn)垂直居...
    DecadeHeart閱讀 1,662評論 0 3
  • 收聽音頻,戳鏈接,舊號itclan已暫停使用,歡迎關(guān)注微信itclanCoder公眾號可收聽更多音頻 前言 關(guān)于網(wǎng)...
    itclanCoder閱讀 8,349評論 3 30
  • 選擇qi:是表達式 標簽選擇器 類選擇器 屬性選擇器 繼承屬性: color,font,text-align,li...
    wzhiq896閱讀 2,114評論 0 2
  • 當看到別人擁有自己沒有的東西時,我們會不由地羨慕。當自己窮困潦倒時,我們會羨慕“富二代”;當我們文筆詞窮時,我們...
    簡單木子閱讀 1,286評論 0 0

友情鏈接更多精彩內(nèi)容