在開發(fā)中經(jīng)常遇到這個(gè)問題冠王,即讓某個(gè)元素的內(nèi)容在水平和垂直方向上都居中,內(nèi)容不僅限于文字蝌以,可能是圖片或其他元素。而且我們希望不要涉及寬度和高度何之,也就是說跟畅,我們不知道父元素的寬高,也不知道內(nèi)容元素的寬高溶推。這篇文章就來總結(jié)一下都有哪些方法可以實(shí)現(xiàn)水平和垂直都居中徊件。
不適合的方案
text-align和line-height
顯然奸攻,使用text-align和line-height的方式更適合單排文字,而不適合本文的需求庇忌。特別是line-height舞箍,無法保證在不知道高度的情況下還能垂直居中。而且就算是文字皆疹,我們也不知道文字有多少行疏橄。
position:absolute、50%和margin:-px
絕大多數(shù)情況下略就,我們可以考慮這種方案捎迫,讓想要居中的元素通過定位和margin為負(fù)值進(jìn)行偏移的方法讓它在垂直方向上居中。這種方案不要求父元素的高度表牢,也就是即使父元素的高度變化了窄绒,仍然可以保持在父元素的垂直居中位置,水平方向上是一樣的操作崔兴。但是這里有一個(gè)問題彰导,就是我們的需求往往是內(nèi)部的這個(gè)元素的寬度高度也不確定,比如是一段文字敲茄,你無法保證這段文字的字?jǐn)?shù)多少位谋,所以通過margin為負(fù)值來偏移在這種情況下行不通。
position:fixed堰燎、0和margin:auto
當(dāng)我們要制作一個(gè)modal dialog彈出框時(shí)掏父,比如彈出居中于屏幕的廣告或登錄框。這個(gè)時(shí)候可以考慮一些相對(duì)于窗口或網(wǎng)頁居中的方案秆剪。
<style>
.container {
position:fixed;
top:0;
right:0;
bottom:0;
left:0;
margin:auto;
}
</style>
<div class="container" style="width: 300px; height: 200px; background: #f1f1f1"> this is a box fixed in center of screen</div>
這里面最重要的是margin: auto;赊淑,對(duì)于塊級(jí)元素而言,確定了自己的寬度之后仅讽,margin:auto可以幫助它居中陶缺,即使在position:fixed時(shí)。不過必須規(guī)定要居中的元素的寬高度洁灵,無法滿足我們的需求饱岸。
position:absolute、0和margin:auto
上面的fixed方案只適合在整個(gè)窗口實(shí)現(xiàn)居中处渣。fixed會(huì)使元素脫離網(wǎng)頁,因此在內(nèi)容流中還是不適用蛛砰。在內(nèi)容流中也想實(shí)現(xiàn)居中罐栈,可以如下:
<style>
.container {
position: relative;
}
.inner-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.inner {
position:absolute;
top:0;
right:0;
bottom:0;
left:0;
margin:auto;
}
</style>
<div class="container">
<p>This is a p</p>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div class="inner-wrapper">
<div class="inner" style="width: 300px;height: 200px;background: #f1f1f1">
this is a box fixed in center of screen
</div>
</div>
</div>
首先是仿造上面一個(gè)方法,使用margin:auto泥畅,只不過使用absolute荠诬。使用absolute定位的話,父級(jí)元素必須也具有position(不為static)。所以把.inner放在一個(gè)有position的父級(jí)元素.inner-wrapper柑贞。這樣.inner相對(duì)于.inner-wrapper就是居中的(前提還是.inner要有寬高)方椎。同理因?yàn)橐O(shè)定寬高,所以不滿足我們的需求钧嘶。
正確的方案
1棠众、display:table和diaplay:table-cell
這個(gè)方案是理解上最容易的,因?yàn)閠able具備垂直居中的屬性有决,所以很容易通過屬性就能實(shí)現(xiàn)闸拿。
<style>
.container {
display: table;
}
.inner {
display: table-cell;
vertical-align:middle;
text-align:center;
}
</style>
<div class="container">
<div class="inner">
you own content
</div>
</div>
這種情況下,我們可以通過隨意改變.inner的寬高书幕,當(dāng)內(nèi)部的內(nèi)容仍然保持居中狀態(tài)新荤。
2、position:absolute台汇、50%和translate
在css3里面提供了translate函數(shù)苛骨,它的主要作用是位移,傳給transform屬性苟呐。
<style>
.container {
position: relative;
}
.inner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
<div class="container">
<div class="inner">
your own content
</div>
</div>
html代碼和上面一樣痒芝。translate(-50%, -50%)將會(huì)將元素位移自己寬度和高度的-50%。這種方法其實(shí)和最上面被否定掉的margin負(fù)值用法一樣掠抬,可以說是margin負(fù)值的替代方案吼野。這樣你就非常容易理解了。這個(gè)方法最厲害的地方是不需要確定.inner的寬高两波,而.container的寬高也不需要手動(dòng)設(shè)置瞳步,如果它自己本身就被撐大的話。這里只是為了演示方便腰奋,才特意給它設(shè)置了寬高单起。
3、vw vh和translate
vh和vw是兩個(gè)比較偏的單位劣坊,是指“viewport的height和width的1%”嘀倒,比如說50vh就是當(dāng)前視口(窗口的高度,實(shí)驗(yàn)中包含了滾動(dòng)條)高度的50%局冰。也就是說vw將獲得和1%差不多的window寬度测蘑。因此用在fixed的時(shí)候更加適合。
<style>
.inner {
position:fixed;
top: 50vh;
left: 50vw;
transform: translate(-50%, -50%);
}
</style>
<div class="inner">
this is a box fixed in center of screen
</div>
其實(shí)和使用50%沒有太大的差別康二,因?yàn)檫@時(shí)top碳胳、left取的50%是相對(duì)于父元素的,和margin沫勿、padding不一樣挨约。如果非得要margin的話味混,就可以從這里衍生出變體:
.inner2 {
position:fixed;
top: 0;
left: 0;
margin: 50vh 0 0 50vw;
transform: translate(-50%, -50%);
}
vh vw只能從窗口的大小去考慮,不適合正常的文本流诫惭。不過有的時(shí)候可以非常有用翁锡,特別是在做全屏應(yīng)用的時(shí)候,比如full page夕土。
4馆衔、:before和display:inline-block
這也是一種處理方式,通過偽類:before在元素內(nèi)增加新元素后在用display:inline-block隘弊,通過高度的處理得到想要的效果哈踱。
<style>
.container{
text-align: center;
}
.container:before {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
.inner {
display: inline-block;
}
</style>
<div class="container">
<div class="inner">
this is a box fixed in center of screen<br>The second line
</div>
</div>
這個(gè)方案是比較特別一些,不是很好理解梨熙。首先开镣,.container水平居中沒問題。接著咽扇,給.container偽類:before設(shè)定為height:100%邪财,這樣可以用一個(gè)偽元素在.container獲得與父元素等高的空間。然后用inline-block和vertical-align: middle改變對(duì)齊的基線质欲,關(guān)于這一點(diǎn)树埠,我也不甚懂,這里有一篇文章可以參考嘶伟。通過:before之后怎憋,.container內(nèi)的行級(jí)元素的對(duì)齊基線就跑到居中的位置,也就實(shí)現(xiàn)了垂直居中對(duì)齊九昧。這個(gè)時(shí)候绊袋,如果里面僅一排文字,其實(shí)可以不用.inner铸鹰,但是上面的例子里面有一個(gè)<br>
癌别,這就不一樣了。如果直接把文字放在.container里面蹋笼,
之前的文字會(huì)基于:before基線展姐,會(huì)保持垂直對(duì)齊的狀態(tài)。但是
之后的文字會(huì)另起一行剖毯,這一行將起始于:before的下一行圾笨,所以會(huì)在:before的100%高度下面,導(dǎo)致被頂出.container逊谋。但是如果把文字放在.inner里面擂达,再讓.inner為inline-block,就可以使.inner和:before處于同一基線涣狗,這樣就讓整個(gè).inner處于垂直居中的狀態(tài)谍婉。
5、css3 flex
css3新增了布局相關(guān)的屬性镀钓,其中flex布局可以非常簡(jiǎn)單地幫我們實(shí)現(xiàn)我們想要的效果穗熬。
<style>
.container {
display: flex;
align-items: center;
justify-content: center;
}
</style>
<div class="container">
<div class="inner">
this is a box fixed in center of screen<br>The second line
</div>
</div>
簡(jiǎn)單解釋一下,當(dāng)display: flex時(shí)丁溅,表示該容器內(nèi)部的元素將按照flex進(jìn)行布局唤蔗。align-items: center表示這些元素將相對(duì)于本容器水平居中,justify-content: center也是同樣的道理垂直居中窟赏。對(duì).container賦予了這些樣式之后妓柜,作為它的內(nèi)部元素.inner自己自覺的居中了。而且這里你會(huì)發(fā)現(xiàn)涯穷,由于沒有使用text-align: center棍掐,.inner里面的文字是不會(huì)居中的,也就是說僅僅.inner這個(gè)容器居中而已拷况。
總結(jié)
從上面的幾種可行的方案作煌,大致可以分為兩類:display對(duì)齊方案、translate位移方案赚瘦。display方案是充分發(fā)揮css的布局特性粟誓,利用布局和UI引擎的特性來控制布局中的對(duì)齊方式。而translate方案則是利用位移起意,通過先50%的位移鹰服,可以是通過position,也可以是通過margin vw vh揽咕,但是完成之后悲酷,在通過translate把元素拉回去,之所以用translate而不是margin是因?yàn)閠ranslate是相對(duì)于元素本身心褐,而margin不是舔涎。