作為一個切圖的頁面仔,工作中總是要用到垂直居中.忙的時候一般就隨便google一個復(fù)制粘貼上去,也從來沒有思考過內(nèi)在的聯(lián)系與原因,但是今天晚上聽聽音樂想看看書的時候,突然心血來潮.擇日不如撞日,就今天吧,夯實一下我的基礎(chǔ),從此讓所有垂直居中都變成紙老虎!!!
那么,先談?wù)労唵蔚拇怪本又邪?
在CSS中想要實現(xiàn)水平居中可以說是十分簡單了,行內(nèi)元素用text-align:center,塊級元素用margin:auto,元素就會乖乖的自己跑到元素水平中間去.
但是這么多年下來,垂直居中已經(jīng)成為了CSS領(lǐng)域的圣杯.
可以說,一個不能解決這個問題的人簡直是寸步難行.不管你想做一個怎樣的網(wǎng)頁,垂直居中都有很大的可能性會用到.但是,它并不簡單,甚至可以說難于登天.
為了解決這個絕世難題,前端開發(fā)者們從各個方面想出了各種不同的點子.之前也許你在百度的某個角落里找到過一些碎片,今天我嘗試將這些碎片組裝起來,還原一個真正的垂直居中,也將自己的基礎(chǔ)進行一次夯實.
1.表格布局法.
第一個想到表格布局法的人已經(jīng)無法考證,但是不得不說這真的是一個Excited的做法.
<body>
<div class="Center-Container is-Table">
<div class="Table-Cell">
<div class="Center-Block">
<!-- CONTENT -->
</div>
</div>
</div>
</body>
<style>
.Center-Container.is-Table { display: table; }
.is-Table .Table-Cell {
display: table-cell;
vertical-align: middle;
}
.is-Table .Center-Block {
width: 50%;
margin: 0 auto;
}
</style>
寫一個表格,將需要居中顯示的內(nèi)容放在表格正中間.自適應(yīng),內(nèi)容變方塊大小也跟著變,兼容性更是不得了.
97.72%.基本沒有不能兼容的.
嗯,所以應(yīng)該說:
表格布局法的優(yōu)點就是兼容性及其變態(tài),基本沒有不能兼容的.缺點也很明顯,需要添加冗余的HTML樣式,這在網(wǎng)頁開發(fā)中一般是不能被接受的.而且display:table有極大的可能性會擾亂整個頁面的布局,使用這種方法還是有一定風(fēng)險的.
2.行內(nèi)塊法.
這個方法的本質(zhì)是使用
display: inline-block;
vertical-align: middle;
讓一個偽元素居于容器中央.
<div class="Center-Container is-Inline">
<div class="Center-Block">
<!-- CONTENT -->
</div>
</div>
<Style>
.Center-Container.is-Inline {
text-align: center;
overflow: auto;
}
.Center-Container.is-Inline:after,
.is-Inline .Center-Block {
display: inline-block;
vertical-align: middle;
}
.Center-Container.is-Inline:after {
content: '';
height: 100%;
margin-left: -0.25em; /* To offset spacing. May vary by font */
}
.is-Inline .Center-Block {
max-width: 99%; /* Prevents issues with long content causes the content block to be pushed to the top */
/* max-width: calc(100% - 0.25em) /* Only for IE9+ */
}
</style>
也沒什么好說的,看代碼基本秒懂的級別.通過加一個翻看公司的項目,好像帶我的老哥使用的就是這種辦法.
但是我個人不喜歡這種方法.
先不說CSS寫的又長又臭,在我看來這完全就是一種Hack,需要死記硬背且難以理解.如果有的選擇,我不會選擇這種方法.
3.基于絕對定位的解決方案.
這是一個古老的方法,具體有多古老?大概是在2013年4月6日.(鏈接至StackOverFlow)網(wǎng)上已經(jīng)有了不少考古學(xué)家做了考證,我就不深挖了.它要求元素具有固定的寬度和高度.
<style>
main{
position:absolute; /*絕對定位*/
top: 50%;/*向下移動父元素高度一半*/
left:50%;/*向右移動父元素寬度一半*/
margin-top: -3em;/*1em為相對于父元素font-size的100%,-3em為向上移動6/2=3em*/
margin-left: -9em;
width: 18em;
height: 6em;
}
</style>
<body>
<main>
<h1>A quick brown fox jump over the lazy dog</h1>
</main>
</body
效果嘛...
可以看到,可以幾乎完美的實現(xiàn)垂直居中.它的原理可以這么解釋:
- top: 50%;
left:50%;
通過這個操作,我們將要添加的元素的左上角固定在了屏幕的正中間. - margin-top: -3em;
margin-left: -9em;
因為知道元素的大小,我們用它的一半作為移動值,將元素進行了移動.
等等,這樣寫好像有點累贅.讓我們用calc()改一下.
<style>
main{
position:absolute; /*絕對定位*/
top: calc(50%-3em);/*向下移動父元素高度一半*/
left:calc(50%-9em)/*向右移動父元素寬度一半*/
width: 18em;
height: 6em;
}
</style>
<body>
<main>
<h1>A quick brown fox jump over the lazy dog</h1>
</main>
</body>
這樣就明顯好得多了.
這種做法看起來在大多數(shù)情況下都可以滿足需求了.但是它有一個很大的局限性,就是我們需要計算偏移的量,這意味著我們必須知道這個元素多大.想到了什么沒有?對啊,CSS為啥沒有This?如果有This的話,這種問題就根本不是問題了.但是很遺憾的是,這個真沒有.
等等,那就沒有辦法了?
不,為什么說后端學(xué)不會CSS呢?因為CSS是一個很.....神奇的東西.我們在translate()這個八竿子打不著的屬性上居然找到了解決方法.translate()就是以自己本身為目標(biāo)進行變換.查查API,略微思考以后,我們可以很輕易的寫出這樣的方法:
<style>
main{
position:absolute; /*絕對定位*/
top: 50%;/*向下移動父元素高度一半*/
left:50%;/*向右移動父元素寬度一半*/
transform: translate(-50%,-50%);
}
</style>
<body>
<main>
<h1>A quick brown fox jump over the lazy dog</h1>
</main>
</body>
這樣就沒什么問題了.
但是缺點還是存在的.首先當(dāng)然是絕對定位的問題,老司機教導(dǎo)我們,能不用絕對定位盡量不要用絕對定位,不然布局出問題了調(diào)試起來很麻煩.然后嘛,就是這樣的問題:
假如元素的高度超過了View層大小,怎么辦?
比如這樣:
可以很明顯的看到,有一半的文字因為超出大小被裁掉了.這可不好玩.
另外,這種寫法我也認為是一種Hack.如果在確定絕對定位可用且方便的情況下,我也許會用它.
4.使用VH?一個不錯的主意.
我想使用translate()來移動元素進行定位.但是我不想用絕對定位,因為絕對定位是邪惡的.
這個問題很值得思考,那么如何在不用絕對定位的前提下進行定位呢?
我知道有朋友可能要搶答了:"用margin啊,我margin一個50%,不就實現(xiàn)居中了?弄這么多破事干啥?"
很遺憾,這是不行的.
<style>
main{
width: 10em;
padding: 1em 1em;
margin: 50% auto 0;
transform: translateY(-50%);
}
</style>
<body>
<main>
<h1>A quick brown fox jump over the lazy dog</h1>
</main>
這令人窒息的效果!令人窒息的滾動條!
深究其原因,margin的百分比是以父元素的寬度作為解析基準(zhǔn)的.等等,父元素的寬度?那我用margin-top,margin-bottom怎么算?難道是不父元素的高度?
很遺憾,還是父元素的寬度為基準(zhǔn).這就可以說是相當(dāng)?shù)目拥?
那就沒有辦法了嗎?不,現(xiàn)在我們有了CSS3,我們有了VH/VW!1VH相當(dāng)于視口高度的1%,1VW相當(dāng)于視口寬度的1%,完美!再也不用擔(dān)心兼容大小屏幕啦!
在這里例子中如果我們使用VH單位:
<style>
main{
width: 10em;
padding: 1em 1em;
margin: 50vh auto 0;
transform: translateY(-50%);
}
</style>
<body>
<main>
<h1>A quick brown fox jump over the lazy dog</h1>
</main>
</body>
完美的效果.
這個方法我認為沒有缺點.但是適用性一般,畢竟只能應(yīng)用于需要視口居中的頁面
5.在座的各位都是垃圾-byFlex
終于講到每天都在用的東西了.一個不會用Flex的前端,真是太可怕了.
我們只需要給父元素聲明display:flex,再給這個元素在設(shè)置margin:auto,就可以做到垂直居中了.
<style>
body{
display: flex;
min-height: 100vh;
margin: 0;
}
main{
margin: auto;
}
</style>
<body>
<main>
<h1>A quick brown fox jump over the lazy dog</h1>
</main>
什么你問我兼容性?
97.19%的兼容性,你還有什么不滿意的?簡單粗暴高效.
但是它真的完美嗎?不見得.
仔細看圖不難發(fā)現(xiàn),在你設(shè)置margin-auto之后,不只是垂直,水平也進行了居中.雖然我們可以用
main{
margin:auto 0 auto 0;
/*等同于margin-top: auto;margin-bottom: auto;*/
}
這樣的寫法讓元素實現(xiàn)只垂直居中,但是畢竟又多考慮了兩個屬性.就沒有更好的辦法了嗎?
5.plus,新的曙光.align-self.
于是我們有了更殘暴的align-self(鏈接至MDN)這一屬性.
它讓垂直居中從圣杯變成了隨便寫寫的東西.
我們只需要:
main{
align-self:center;
}
就能夠徹底實現(xiàn)上面margin來margin去的效果.
總結(jié)的比較粗淺,所幸沒有留下什么疑問.這個周末也過得非常充實,以后再碰到垂直居中的問題再也不會去搜啦!
我的blog是blog.codermagefox.com 歡迎來看看!