整理:子容器垂直居中於父容器的方案

本文在evernote裏有備份。若是evernote的閱讀區域嫌窄了,那麼能夠把這個連接拖入書籤並點擊javascript:jQuery("#container").width(980);javascript


本文從這個回答整理而來。對於當今出現的一些CSS垂直居中的方案,這篇文章將會系統地審視它們,從實用角度進行評估。css

不羅嗦,先上圖:html

請輸入圖片描述


考量需求及難度

爲避免混淆,本文中所說的父容器子容器都不是相對的,而對應着以下文檔結構裏面的.outer.inner容器:java

<div class="outer"> <!-- 父容器 -->
     <div class="inner"> <!-- 子容器 -->
          ... <!-- 子容器內部內容 -->
     </div>
     ... <!-- 父容器內其餘的子元素 -->
</div>

咱們從以下角度來評估:css3

  • 父容器/子容器的高度是否可變
  • 是否須要手工計算
  • 子元素溢出時父元素是截斷、被撐高仍是保留滾動條
  • 固然,還有兼容性

高度相關

代碼 效果
height:100px; 定高
height:auto 不定高,自適應於自身的content-box
height:50% 不定高,自適應於包含塊

出現了 3(定高/自適應於外部/自適應於內部) ^ 2 (父容器/子容器) =9 種情形,搭配見下:web

父容器 子容器 難度 解(tu)說(cao)
定高 定高 簡單 快速開發時就是這樣
定高 自適應於內部 稍難 常見的需求
定高 自適應於外部 簡單 手工算一算就行了
自適應於內部 定高 簡單 變相定高,高度放在內層,方便解耦
自適應於內部 自適應於內部 稍難 留白固定,罕見的需求
自適應於內部 自適應於外部 WTF 折騰出這種需求,不以爲害臊嗎
自適應於外部 定高 困難 適配全部屏幕的slideshow
自適應於外部 自適應於內部 困難 普適性更高的slideshow
自適應於外部 自適應於外部 稍難 一個模塊(或大小不定的頭像),出如今大小不定的位置

溢出相關

子容器溢出表明子容器高度大於父容器高度的情形。segmentfault

  • 子容器溢出時,被父容器截斷。父容器overflow:hidden
  • 子容器溢出時,把父容器撐高。父容器height:auto;overflow:visibledisplay:table-cell等等。
  • 子容器溢出時,父容器出現滾動條。父容器overflow:scrolloverflow:auto

很顯然,子容器溢出時,被父容器截斷的情形沒法和父容器自適應於子容器共存。瀏覽器

兼容性

  1. IE六、IE7:老而不死的瀏覽器,瀏覽器還沒有統1、IE一家獨大之時的遺毒,一大堆bug等着你。
  2. IE8:IE8起全面支持CSS2.1,剩下一些稍微少坑爹那麼一點點的bug。
  3. IE9。尷尬的產物,微軟第一次搭上CSS3的末班車。
  4. IE10+與其餘現代瀏覽器(終於能夠和其餘瀏覽器並列了……IE10淚目)。

四、三、二、1的兼容難度是一步步變難,兼容到四、三、二、1所對應的代碼量/工做量是100%、102%、120%、300%的關係。ide

在這裏僅僅考量IE6/7,IE8的無bug實現的兼容性。IE9+的兼容性,對於文中提到的全部方案都是可行的。wordpress

其餘

  1. 是否須要手動計算/須要calc屬性進行輔助計算

若是須要手動計算,若界面進行重構,而居中的需求不變,就須要從新計算。比較費時費事。佈局也相對不夠靈活。


方案彙總

CSS 版本 佈局類型 方案
CSS 2.1 普通流,塊級佈局 父容器上下等padding
子容器上下等margin
普通流,行內佈局 父容器line-height=height
子容器所在的line-box的line-height=父容器的height
普通流,塊級table佈局 父容器display:table-cell,子容器vertical-align
子容器被table、tr、td包裹
絕對定位佈局 子容器絕對定位,top:50%,負margin
子容器絕對定位,top:0,bottom:0,margin:auto
普通流,塊級佈局 background代圖片background-position
CSS3 絕對定位佈局 子容器絕對定位,top:50%,translateY(-50%)
普通流,塊級佈局 backgournd代圖片backgournd-size
普通流,flexbox佈局 flexbox

方案評估

1. 普通流,塊級佈局 (css2.1)

方案 兼容性 父容器 子容器 子容器溢出 其餘
IE8 IE6/7 定高 自適應於內部 自適應於外部 定高 自適應於內部 自適應於外部 撐高 被截斷 不需手工計算
父容器上下等padding √* × √* × √* ×
子容器上下等margin √* × √* × × ×
background代圖片background-position × × ×

1.1. 父容器上下等padding & 子容器上下等margin

最基礎的方案就是這樣,手工算好每個容器的高度和補白/位移須要的內容,簡單粗暴:

/*父子均定高,父容器上下等padding*/
.outer{ height: 100px; padding-top: 40px ; }
.inner{ height: 100px; }
/*父子均定高,子容器上下等margin*/
.outer{ height: 180px; overflow: hidden; *zoom: 1; }/*父容器給予BFC以免子容器margin併到父容器上*/
.inner{ height: 100px; margin-top: 40px ; }

父子都須要自適應於內部時:

/*父子均自適應於內部,父容器上下等padding*/
.outer{ height: auto; padding-top: 40px ; padding-bottom: 40px ; }
.inner{ height: auto; }
/*父子均自適應於內部,子容器上下等margin*/
.outer{ height: auto; overflow: hidden; *zoom: 1; }/*父容器給予BFC和haslayout,以免子容器margin併到父容器上*/
.inner{ height: auto; margin-top: 40px ; margin-bottom: 40px ; }

說明:

  1. 需求:父子都須要自適應於內部的解決方案裏,是把留白的高度固定,這種需求其實不多見。
  2. 可缺省:height:auto能夠省去,這是默認值。
    對於塊級元素,默認是height:auto;width:auto;
    width的auto值是自適應於這個元素的包含塊的寬度,而height自適應於這個元素的content-box的高度

  3. 自適應:父子容器都可以自適應於內部;也能夠父容器自適應,子容器定高。
    由於height:auto時,計算高度值的依賴方向是從外往內。

  4. 自適應:爲什麼在這倆方案裏不允許出現父容器或子容器自適應於外層呢?
    由於對於height來講,它的百分比值是乘以包含塊的height,但padding-top/padding-bottom/margin-top/margin-bottom的百分比值是乘以包含塊的width,而非咱們但願的height。

  5. 溢出:

* 父容器上下等padding時,父容器定高時,子容器溢出padding-edge的部分會被截斷。
* 子容器上下等margin時,父容器自適應於內部,父容器只會被撐高,永遠沒法被截斷。
* 其餘情形,截斷都沒有什麼意義

1.3. background代圖片background-position

在子容器是<img>標籤時,能夠直接使用background來替代它。也能夠算得上一種方案。

.inner { background-image: url("...");
   background-position: 50% 50%;/*注,火狐不支持background-position-y的屬性設置*/ }

說明:

  1. 自適應:沒法自適應於外部容器,CSS2.1階段,background沒法相對於容器伸縮。

  2. 溢出:背景溢出的情形,直接會被截斷。

  3. 其餘:你甚至能夠把inner的標籤省掉,直接把背景放到outer之上

2. 普通流,行內佈局 (css2.1)

方案 兼容性 父容器 子容器 子容器溢出 其餘
IE8 IE6/7 定高 自適應於內部 自適應於外部 定高 自適應於內部 自適應於外部 撐高 被截斷 不需手工計算
父容器line-height=height √* × × × ×
子容器所在的line-box的line-height=父容器的height √* √* × ×

2.1 父容器line-height=height

「父容器line-height=height」,這個方案在於將子容器當作行內元素呈遞,並設置vertical-align,line-box和block-box的高度持平,就完成了垂直居中的的效果。

.outer { line-height: 100px; height: 100px; font-size: 0; }
.inner { display:inline-block; vertical-align:middle; font-size: 16px; }

爲什麼須要font-size:0?由於vertical-align:middle的定義是:元素的中垂點與父元素的基線加1/2父元素中字母x的高度對齊。所以在font-size>0時,元素將會在baseline上出現必定的偏移,偏移量跟這個字號下的x字母的高度有關。

能夠在jsFiddle中看到對比:

不使用font-size:0

http://jsfiddle.net/humphry/haaaM/

使用font-size:0

http://jsfiddle.net/humphry/7zCEm/

說明:

  1. 兼容性:沒有涉及relative和absolute定位,佈局時相對無痛。

  2. 兼容性:這個方案是IE6\7不支持的,緣由不詳(只知道inline-blockvertical-align的標準誕生於IE8以後),也沒有時間研究。2014年了,有點追求好嗎。

  3. 自適應:子容器能夠輕鬆作到自適應於內部、外部或者定高,但在這個方案裏,父容器必須定高,由於line-height的百分比單位是相對font-size來講的。

  4. 溢出:子容器溢出時會變成頂對齊,這是由於,line-box 的高度跟內部最高的 inline-box 相等,於是line-box 能夠被撐高,從上往下排一個個排列下來,從而失去了居中的效果。換句話說,子元素溢出時,父容器能夠自適應於內部。

  5. 其餘:line-heightfont-size是一個能夠繼承的屬性,在這種方案裏面,必然會致使line-heightfont-size被繼承,所以在須要排版子容器時,須要複寫line-heightfont-size

2.2 子容器所在的line-box的line-height=父容器的height

對上面的方法不兼容IE6\7且不能作到父容器自適應的方面,能夠這樣改進:

  1. 把子容器當成行內元素呈遞
  2. 構建一個行內級別的鉤子元素,緊挨着子容器,以使用:before/:after僞元素自制一個文本節點、或<span>或任意一個inline級別的標籤、或者一個1*1的圖片。
  3. 讓鉤子元素撐滿容器高度,這意味着它須要成爲inline-box元素,而後設置height:100%便可。
  4. 如今,子容器所在的 line-box 的 line-height = 父容器的 height。
  5. 最後,給子容器和鉤子元素設置vertical-align:middle,讓它們的中心線對齊于于父容器的middle-line,就能作到垂直居中。

http://jsfiddle.net/humphry/86dsC/21/

如今這個佈局能夠自動生成,詳見@林小志的css小工具:圖片垂直居中span

(若是須要水平居中,那麼這個額外的節點,須要移去自身所佔的距離,通常使用margin-left:-1pxmargin-right:-1px,取決於鉤子在子容器的哪一邊。)

說明:

  1. 兼容性:沒有涉及relative和absolute定位,佈局時相對無痛。

  2. 兼容性:inline-box標籤之間的任意數量的空白符:ASCII 空格 (&#x0020;)、ASCII 製表符 (&#x0009;)、ASCII 換頁符 (&#x000C;)、零寬度空格 (&#x200B;) 會被瀏覽器解析成一個空格,形成間隙。須要經過改變HTML結構/使用負margin等來去掉這個間隙

  3. 兼容性:這個方案有必定hack量,去掉inline-box的空格間隙是一部分,display:inline-block的IE6\7 hack是另外一部分。

  4. 自適應:父容器能夠自適應於外部了,由於這裏不須要在任何地方知道父容器的高度。

  5. 溢出:子容器溢出時會變成頂對齊,緣由同上。

3. 普通流,塊級table佈局 (css2.1)

方案 兼容性 父容器 子容器 子容器溢出 其餘
IE8 IE6/7 定高 自適應於內部 自適應於外部 定高 自適應於內部 自適應於外部 撐高 被截斷 不需手工計算
父容器display:table-cell,子容器vertical-align × × × ×
子容器被table、tr、td包裹 √* √* ×

3.1. 父容器display:table-cell,子容器vertical-align

這個方案依然是用到vertical-align:middle,只不過須要放到做爲display:table-cell的元素之上。

http://jsfiddle.net/humphry/7AMF9/2/

這個佈局也能夠自動化生成:見@林小志的css小工具:圖片垂直居中 table cell

說明:

  1. 兼容性:IE6/7不兼容display:table-cell

  2. 自適應:子容器沒法自適應於父容器,高度沒法使用百分比單位,由於根據渲染規則,display:table-cell的元素的包含塊是它父級的display:table的元素。

  3. 溢出:父元素就算給定高度,設置overflow,也不會致使溢出隱藏;在子元素溢出的時候,父容器不能保有自身設置的高度,直接會被撐高。

  4. 其餘:display:tabel-cell自己讓不少屬性無效。

3.2. 子容器被table、tr、td包裹

爲了可讓子容器有百分比高度,咱們能夠直接構建一個表結構出來:

http://jsfiddle.net/humphry/Ns4RK/8/

說明:

  1. 兼容性:這是一個全兼容的方案。

  2. 自適應:如今「父級」的自適應要求均可以獲得知足,只不過這裏的「父級」指的是包在最外層的table

  3. 溢出:父元素就算給定高度,設置overflow,也不會致使溢出隱藏。

  4. 其餘:文檔結構變複雜了,語義被拋棄了。

  5. 其餘:display:tabel-cell自己讓不少屬性無效。

  6. 其餘:能夠把這個方案裏的<table>換成display:table的其餘元素,tr、td亦然:
    http://jsfiddle.net/humphry/KxKc8/
    我的以爲……徒增煩惱爾。

4. 絕對定位佈局 (css2.1)

方案 兼容性 父容器 子容器 子容器溢出 其餘
IE8 IE6/7 定高 自適應於內部 自適應於外部 定高 自適應於內部 自適應於外部 撐高 被截斷 不需手工計算
子容器絕對定位,top:50%,負margin √* × × × ×
子容器絕對定位,top:0,bottom:0,margin:auto × √* × ×

4.1 子容器絕對定位,top:50%,負margin

.outer{ position: relative; }
.inner{ position: absolute; top: 50%; height: 20px; margin: -10px; }

這是互聯網上能找到的最多的關於垂直居中的方法。咱們不相信瀏覽器,使用手算,將子元素挪去自身高度的50%。

說明:

  1. 兼容性:子元素和父元素都須要設置position,這就意味着IE6\7下面的數十個友情附贈的美好bug。

  2. 自適應:子元素必須定高,不定高算不出來負margin。不能夠是百分比高度單位,由於margin-top的百分比,是相對其包含塊的寬度而言的。

  3. 自適應:父容器能夠自適應於內部,只不過不是這個子元素,而是父容器內部其餘的元素。子元素對外層高度、寬度塌陷,不能撐寬/撐高父容器了。

  4. 溢出:這個方案也能夠支持子元素高度溢出的情形。

  5. 其餘:須要手動計算子元素1/2的高度是多少。

4.2 子容器絕對定位,top:0,bottom:0,margin:auto

.outer{ position: relative; }
.inner{ position: absolute; margin-top: auto; margin-bottom : auto;
    top: 0; bottom: 0; height: 20px; }

這個的原理寫在CSS2.1中:

‘top’ + ‘margin-top’ + ‘border-top-width’ + ‘padding-top’ + ‘height’ + ‘padding-bottom’ + ‘border-bottom-width’ + ‘margin-bottom’ + ‘bottom’ = 包含塊的高度

在其餘值不是auto的時候,margin-topmargin-bottom是能夠根據上式算出的,原理相似於水平居中。

說明:

  1. 兼容性:這個方案僅僅支持IE8+。IE6和IE7因爲對同時定義topbottom屬性的樣式解析與 css2.1 不一致,不支持這種定位方式。

  2. 自適應:父容器能夠自適應於內部,只不過不是這個子元素,而是父容器內部其餘的元素。緣由同上。

  3. 自適應:這個方案須要子容器有一個固定的高,或百分比自適應於外部。它的高度不能是height:auto,由於這樣會使得上面的算式裏auto出如今三個地方,瀏覽器沒法計算出相應margin值。

  4. 溢出:這個方案也能夠支持子元素高度溢出的情形。

  5. 其餘:徹底不用算,耶!

5. css3一系列佈局

方案 兼容性 父容器 子容器 子容器溢出 其餘
IE8 IE6/7 定高 自適應於內部 自適應於外部 定高 自適應於內部 自適應於外部 撐高 被截斷 不需手工計算
子容器絕對定位,top:50%,translateY(-50%) × × √* ×
backgournd代圖片backgournd-size × × √* ×
flexbox × ×

5.1 子容器絕對定位,top:50%,translateY(-50%)

.outer{ position: relative; }
.inner{ position: absolute; top: 50%; transform: translateY(-50%);}

原理同上,僅僅是僅僅是用translate替換了負margin,由於translate的百分比偏移量是容器自己的。

說明:

  1. 兼容性:ie9+(但,從好處來說,其實這個兼容性已經徹底不須要考慮IE6~8的相對/絕對佈局bug了)

  2. 自適應:子元素能夠不指定高度,也能夠相對父級高寬作百分比設置,也包括定寬,很是靈活

  3. 自適應:父容器能夠自適應於內部,只不過不是這個子元素,而是父容器內部其餘的元素。緣由同上。

  4. 溢出:支持子元素溢出隱藏,或者溢出顯示。

  5. 其餘:你會讓代碼陷入一個前綴的海洋……

.inner{
    -webkit-transform:translate(-50%, -50%);
    -moz-transform:translate(-50%, -50%);
    -ms-transform:translate(-50%, -50%);
    -o-tranform:translate(-50%, -50%);
    transform:translate(-50%, -50%);
}

5.2 backgournd代圖片,backgournd-size

.inner{ background-image: url("...") ; background-size: cover ; height: 100% ; }

說明:

  1. 兼容性:只能是IE9+和現代瀏覽器

  2. 自適應:背景能夠任意自適應於外部容器,或者定高寬。也可讓子容器自適應於內部內容,背景自適應於子容器。

  3. 溢出:支持背景溢出隱藏,但沒法溢出顯示。好消息是,可使用background-clip指定背景從哪裏消失。

  4. 其餘:你甚至能夠把.inner的標籤省掉,直接把背景放到.outer之上

5.3 flexbox

// TBD
// 很抱歉,因爲對flexbox沒有深刻的瞭解,我尚未試驗出flexbox在子元素溢出時也能保持居中的解決方案……最好的結果是子元素被拉伸(= =)。有人有過實例嗎?

說明:

  1. 兼容性:只能是IE9+和現代瀏覽器

  2. 其餘:兼容性是我目前已知的東西……


請輸入圖片描述
相關文章
相關標籤/搜索