事實上,每次面試前端必問的問題就是這個。及其常見的需求,看起來彷佛很是簡單,可是實現起來很費勁,尤爲是涉及尺寸不固定的元素。css
本篇文章將介紹比較流行的幾種方法。html
<body> <div id="ghost"></div> <span> hello </span> </body>
#ghost { display: inline-block; height: 20em; vertical-align: middle; }
本質上是利用了內聯元素的 vertical-align 屬性,經過將此屬性置爲middle,同一行內的內聯元素都將以設置這一屬性的內聯元素的基線對齊。前端
基於inline-block特有的屬性:擁有內聯元素的特性同時能夠定義寬高,咱們能夠設置一個ghost行內塊用於定義高度,再讓其餘內聯元素與其對齊,實現垂直居中。面試
固然咱們也能夠將其它元素置爲行內塊,再設置寬度並添加text-align使其水平居中。瀏覽器
總結一下,此方法太過hack。函數
<div id="main"> <div id="child"> hello </div> </div>
#main { background-color: green; height: 20em; width: 20em; position: relative; } #child { position: absolute; background: yellow; top: 50%; left: 50%; height: 10em; width: 10em; margin-top: -5em; margin-left: -5em; }
顯然,這種方法的原理是:先利用絕對定位將這個元素的左上角放置與父元素的正中間,再利用負邊距將它向左上移動它自己的一半。佈局
若是藉助calc()函數能夠說明得更加清楚:flex
#child { position: absolute; top: calc(50%-5em); left: calc(50%-5em); height: 10em; width: 10em; }
實際中大多數時候咱們並不知道子元素的實際寬高。flexbox
若是你屬性translate()函數,你必定知道當它的參數爲百分比時,它會按照元素自己的百分比值進行變換,咱們能夠經過這個方法完全擺脫對尺寸的依賴!spa
#child { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
看起來已經完美解決了,可是它還有如下的缺陷:
若是咱們不採用絕對定位,對子元素設置margin使其左上角置於父元素中點,再用translate重複上一種方法的操做,是否能夠實現呢?
答案是不能夠,由於margin的百分比是以父元素的寬度爲基準的,即使是top和bottom也是! 沒錯,很扯。
若是僅僅想要垂直於視口,咱們能夠採用css中相對於視口的單位 vw、vh、vmin、vmax
#child { margin:50vh auto 0; transform: translateY(-50%); }
它只能基於視口居中。
flex固然是將來的趨勢,上面的一切均可以理解成爲了照顧老舊的瀏覽器的猴戲(雖然translate和視口單位的兼容性也不怎麼好)。
<body> <div id="main">hello</div> </body>
#main { margin: auto; } body { display: flex; }
啊,很難受。使用flexbox時,margin:auto不只在水平方向上將元素居中,垂直方向上也是如此。
若是你熟悉flex的話,其實還有多種實現方式。
body { display: flex; justify-content: center; align-items:center; }
或者對子元素單獨設置交叉軸對齊方式:
body { display: flex; justify-content: center; } #main { align-self:center; }