"44年前我們就把人類送上了月球了,但現在我們仍然無法在css中實現垂直居中 -James Anderson"
難題
在CSS中對元素進行水平居中是非常簡單的;如果是一個行內元素,就對父元素設置text-align:center;如果是一個它是一個塊級元素,就對自身應用margin:auto.然而考慮到代碼的DRY和較強的可維護性,如果要對一個元素進行垂直居中,可能是令人頭皮發麻的一件事情了.
就這樣在前端開發圈內看似及其常見的需求,從理論上似乎極其簡單,在實踐中,它往往難如登天,當涉及尺寸不固定的元素時尤為如此.
為了解決這一"絕世難題",於是前端開發者們殫精竭慮,腦洞大開,琢磨出了各種解決方案,大多數並不實用.
一路走來走了不少彎路,希望初入前端的小伙伴們可以走的更加通暢,總結分享給大家:
下面就讓我們來探索現代css的強大威力:
基於表格布局法的解決方案
利用表格的顯示模式,需要用到一些冗余的HTML元素
思路來源:
<table style="width:100%;height:100%;">
<tr>
<td style="text-align: center; vertical-align: middle;">
Unknown stuff to be centered.
</td>
</tr>
</table>
html,body{
height:100%;
}
摘自:https://css-tricks.com/centering-in-the-unknown/
我們發現在table中vertical-align: middle;實現了自動垂直居中.
See the Pen css-table-verticalMiddle by okaychen (@okaychen) on CodePen.
基於曾經在網頁早期風靡一時的表格布局法:實現了垂直居中
但是由於表格布局法逐漸的退出舞台,這種方法也漸漸的不為所用
基於絕對定位的解決方案
早期實現垂直居中方法,要求具有固定的寬度和高度:
main{
position:absolute;
top:50%;
left:50%;
magin-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;
}
顯然這個方法最大的局限性就是他要求元素具有固定寬度和高度.我們知道在通常情況下,固定寬度和高度的情況是極少的,對於那些需要居中的元素來說,其尺寸往往是由其內容決定的.如果能夠找到一個屬性的百分比以元素自身的寬高作為基准,那么難題就迎刃而解!遺憾的是,對於大多數的css屬性(包括margin)來說,百分比都是以其父元素的尺寸為基准進行解析的
css領域有一個很常見的現象,真正的解決方案往往來自我們最意想不到的地方:利用css變形屬性,
當我們在進行
translate()變形函數中使用百分比值時,是以這個元素位基准進行轉換和移動的,而這正是我們所需要的.
main{
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}
See the Pen css-lineCenter-position by okaychen (@okaychen) on CodePen.
從codepen中看到,利用css變形技巧,這個容器已經完美居中,滿足我們的期望.
但是沒有任何技巧十全十美,我們需要注意幾點:
-
我們有時不能選擇絕對定位,他對整個布局影響太過強烈
-
如果需要居中的元素已經在高度上超過了視口,那它的頂部部分就會被視口裁掉
-
在某些瀏覽器中,這個方法可能會導致元素的顯示模糊,因為元素可能會被放置在半個元素上.可以用一個偏hack的手段來修復
transform-style:preserve-3d
基於視口的解決方案
假設我們不使用絕對定位,仍然采用translate()技巧來把這個元素以其自身寬高的一半為距離進行移動;但是在缺少left和top的情況下,如何吧這個元素放在容器正中心呢?
我們的第一反應很可能用margin屬性的百分比值來實現,就像這樣:
main{
width:18em;
padding:1em 1.5em;
margin:50% auto 0;
transform:translateY(-50%);
}
但是卻產生了十分離譜的效果.原因在於margin的百分比值是以父元素的寬度作為解析基准的
在CSS值與單位(第三版)定義了一套新的單位,稱為視口相關的長度單位
-
vm是與視口寬度相關的.1vm相當於視口的1%
-
與vw類似,1vh相當於視口的1%
-
當視口寬度小於高度時,1vmin等於1vw,否則等於1vh
-
當視口寬度大於高度時,1vmax等於1vw,否則等於1vh
在這個例子中,我們適用外邊距的是vh單位
main{
width:18em;
padding:1em 1.5em;
magin:50vh auto 0;
transform:translateY(-50%);
}
See the Pen css-lineCenter-vm by okaychen (@okaychen) on CodePen.
我們可以看到,其效果堪稱完美.這個技巧更適合於在視口中居中的場景.
基於Flexbox的解決方案
這是毋庸置疑的最佳解決方案,因為Flexbox(伸縮盒)是專門針對這類需求所設計的.現代瀏覽器對於Flexbox支持度已經相當不錯了
我們只需要兩行聲明即可:先給這個待定居中元素的父元素設置display:flex(在使用的例子中是body元素),在給這個元素設置我們在熟悉不過的margin:auto
body{
display:flex;
min-height:100vh;
margin:0;
}
main{
margin:auto;
}
Flexbox還有一個好處就是,它可以將匿名容器(即使沒有節點包裹的文本節點)垂直居中.
<main>center me,place!</main>
借助Flexbox規范所吸引人的align-items和justify-content屬性,我們可以讓它內部文本也實現居中
main{
display:flex;
align-items:center;
justify-content:center;
width:18em;
height:10em;
}
把所有的東西都對齊吧!
根據盒對齊模型(第三版)的計划,在未來,對於簡單的垂直居中的要求,我們完全不需要動用特殊的布局模式.我們只需要這行代碼就可以搞定
align-self:center;
不知不覺間,我們身邊的瀏覽器都開始讓它成為現實(但是路途還很遙遠:IE10及更早版本不支持,Safari 7.0 及更早版本使用-webkit前綴)

因為使用博客園的Markdown編輯器,codepen部分無法顯示,建議跳到我的博客- -;
原文地址:http://www.chenqaq.com/2017/12/07/css-verticalMiddle/
參考資料
-
《CSS Secrets 》
-
CSS值與單位:http://w3.org/TR/css-values
-
CSS伸縮盒布局模型:http://w3.org/TR/css-flexbox
-
CSS盒對齊模型:http://w3.org/TR/css-align
