把簡單做好也不簡單-css水平垂直居中

Icarus發表於2016-12-17

44年前我們把人送上月球,但在CSS中我們仍然不能很好實現水平垂直居中。

作者:Icarus
原文連結:xdlrt.github.io/2016/12/15/…

水平垂直居中有相同點也有不同點,接下來討論常見的方式。

如無特殊說明,以下示例html均為:

<div class="md-warp">
    <span class="md-main"></span>
</div>複製程式碼

基礎樣式為:

.md-warp{
    width: 400px;
    height: 300px;
    max-width: 100%;
    border: 1px solid #000;
}
.md-main{
    display: block;
    width: 100px;
    height: 100px;
    background: #f00;
}複製程式碼

水平居中

margin法

需要滿足三個條件:

  • 元素定寬
  • 元素為塊級元素或行內元素設定display:block
  • 元素的margin-leftmargin-right都必須設定為auto
    三個條件缺一不可。

demo:

.md-main{
    margin: 0 auto;
}複製程式碼


定位法

需要滿足三個條件:

  • 元素定寬
  • 元素絕對定位,並設定left:50%
  • 元素負左邊距margin-left為寬度的一半

demo1:

.md-warp{
    position: relative;
}
.md-main{
    position: absolute;
    left: 50%;
    margin-left: -50px;
}複製程式碼


有些時候我們的元素寬度可能不是固定的,不用擔心,我們依然可以使用定位法實現水平居中,此時需要用到css3中的transform屬性中的translate,可以使元素移動時相對於自身的寬度和高度。
需要注意,這種方法需要IE9+才可以實現。

demo2

.md-warp{
    position: relative;
}
// 注意此時md-main不設定width為100px
.md-main{
    position: absolute;
    left: 50%;
    -webkit-transform: translate(-50%,0);
    -ms-transform: translate(-50%,0);
    -o-transform: translate(-50%,0);
    transform: translate(-50%,0);
}複製程式碼

不定寬

文字水平居中

對於單行文字來說,直接使用text-align: center即可。
多行文字可以看作一個塊級元素參考margin法和定位法。

垂直居中

定位法

和水平居中類似,只是把left:50%換成了top:50%,負邊距和transform屬性進行對應更改即可。

優點:能在各瀏覽器下工作,結構簡單明瞭,不需增加額外的標籤。

demo1:

.md-warp{
    position: relative;
}
.md-main{
    position: absolute;
    /* 核心 */
    top: 50%;
    margin-top: -50px;
}複製程式碼


運用css3中的clac()屬效能簡化部分程式碼:

.md-warp{
    position: relative;
}
.md-main{
    position: absolute;
    /* 核心 */
    top: calc(50% - 50px);
}複製程式碼


demo2

.md-warp{
    position: relative;
}
.md-main{
    position: absolute;
    top: 50%;
    // 注意此時md-main不設定height為100px
    -webkit-transform: translate(0,-50%);
    -ms-transform: translate(0,-50%);
    -o-transform: translate(0,-50%);
    transform: translate(0,-50%);
}複製程式碼

不定高

單行文字垂直居中

需要滿足兩個條件:

  • 元素內容是單行,並且其高度是固定不變的。
  • 將其line-height設定成和height的值一樣
<div><span>這是一段文字</span></div>複製程式碼
div{
    width: 400px;
    height: 300px;
    border: 1px solid #000;
}
span{
    line-height: 300px;
}複製程式碼
這是一段文字

以上是一些常規辦法,接下來是利用CSS3新特性實現的示例。

視窗單位的解決辦法(垂直居中)

如果想避免使用絕對定位,我們仍然可以利用translate()方法,其值剛好是元寬度和高度的一半。但是,我們如何不使用top和left將元素從top和left移動50%的偏移量呢?

首先想到的是給margin屬性一個百分數,像這樣:

.md-main{
    margin: 50% auto 0;
    transform: translateY(-50%);
}複製程式碼

效果如下所示:



我們發現並沒有出現預想的結果,這是因為margin的百分比計算是相對於父容器的width來計算的,甚至包括margin-topmargin-bottom

我們如果仍然想讓元素在視窗中居中,還是有救的。CSS3定義了一種新的單位,稱為相對視窗長度單位。

以下摘自w3cplus
vw是相對於視窗的寬度。與你預期剛好相反,1vw相當於視窗寬度的1%,而不是100%
vw相似的是,1vh相當於視窗高度的1%
如果視窗的寬度小於高度,1vmin等於1vw,反之,如果視窗寬度大於高度,1vmin等於1vh
如果視窗的寬度大於高度,1vmax等於1vw,反之,如果視窗寬度小於高度,1vmax等於1vh

在上個示例的基礎上,我們需要給margin設定vh單位:

.md-warp{
    position: relative;
}
.md-main{
    position: absolute;
    margin: 50vh auto 0;
    transform: translateY(-50%);
}複製程式碼

注意:這種方法最大的侷限是隻能適用於元素在視窗中垂直居中,如果是在區域性的某個地方就無能為力了。

Flexbox的解決方案

如果不考慮瀏覽器的相容性,Flexbox無疑是最好的解決方案,因為它的出現就是為了解決這樣的問題。

完成這項工作只需要兩個樣式,在需要水平垂直居中的父元素上設定display:flex和在水平垂直居中的元素上設定margin:auto

.md-warp{
    display:flex;
}
.md-main{
    margin: auto;
}複製程式碼


Flexbox的實現文字的水平垂直居中同樣很簡單。

.md-warp{
    display:flex;
}
.md-main{
    display: flex;
  align-items: center;
  justify-content: center;
    margin: auto;
}複製程式碼

我是字啊

補充:

inline-block配合偽類的解決方案

.md-warp{
  font-size: 0;
}
.md-warp:before{
  content:'';
  display:inline-block;
  width: 0;
  height:100%;
  vertical-align:middle;
}
.md-main{
  display:inline-block;
  vertical-align:middle;
  font-size: 14px;
}複製程式碼

引自demo.doyoe.com/css/alignme…
首先要了解垂直方向的對齊排版需使用 vertical-align ,並且只應用於inline level, inline-block level 及 table-cells 元素上;其次 vertical-align 的對齊就基於每個 line box(行框) 的,簡單的說,inline level元素按照 Normal flow 水平排版出一行就會形成一個line box,其高度由內容形成,如果換行,則又是另一個line box,所有一段文字可能會分佈在多個line box裡,這些不重疊的line box被稱作為a vertical stack of line boxes(一個垂直堆疊的線框集合)這些。
換句話說,我們的垂直居中是要在每個line box中進行處理。而上例中我們想讓一行文字在名叫demo的高100px的容器裡垂直居中,這時有個問題就是demo容器並非該行文字的line box,所以就算定義vertical-laign為middle也無法讓該行文字在demo容器中垂直居中。我們知道line box的高度是由內容形成的,這時我們可以額外建立一個與該行文字處於同一line box的元素,同時將新增元素的高度定義為與demo容器相同,此時line box的高度將與demo一致,文字將會在line box內垂直居中,即同樣實現了在demo容器中垂直居中。

絕對垂直居中

.md-warp{
  position: relative;
}
.md-main{
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin: auto;
}複製程式碼

常用在彈出層的定位中。

結語

  • 絕對定位通常不是一個很好的選擇,因為它對整體的佈局影響相當的大。
  • 在一些瀏覽器中,可能會導致元素出現略微的模糊,那是因為元素有可能被放置在半個畫素位置上。我們可以通過transform-style:preserve-3d來解決,但這是一個Hack手段,不能保證它不會過時。

以上各種方法稍加組合即可同時實現水平和垂直居中,這些就是平時用到較多的一些居中的方法,希望大家看完之後有收穫:)

相關文章