本文在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:visible
或display:table-cell
等等。overflow:scroll
或overflow:auto
很顯然,子容器溢出時,被父容器截斷的情形沒法和父容器自適應於子容器共存。瀏覽器
四、三、二、1的兼容難度是一步步變難,兼容到四、三、二、1所對應的代碼量/工做量是100%、102%、120%、300%的關係。ide
在這裏僅僅考量IE6/7,IE8的無bug實現的兼容性。IE9+的兼容性,對於文中提到的全部方案都是可行的。wordpress
若是須要手動計算,若界面進行重構,而居中的需求不變,就須要從新計算。比較費時費事。佈局也相對不夠靈活。
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 |
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其餘 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自適應於內部 | 自適應於外部 | 定高 | 自適應於內部 | 自適應於外部 | 撐高 | 被截斷 | 不需手工計算 | |
父容器上下等padding | √ | √ | √ | √* | × | √ | √* | × | √ | √* | × |
子容器上下等margin | √ | √ | √ | √* | × | √ | √* | × | √ | × | × |
background代圖片background-position | √ | √ | √ | √ | √ | √ | × | × | × | √ | √ |
最基礎的方案就是這樣,手工算好每個容器的高度和補白/位移須要的內容,簡單粗暴:
/*父子均定高,父容器上下等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 ; }
說明:
可缺省:height:auto
能夠省去,這是默認值。
對於塊級元素,默認是height:auto;width:auto;
width的auto值是自適應於這個元素的包含塊的寬度,而height自適應於這個元素的content-box的高度
自適應:父子容器都可以自適應於內部;也能夠父容器自適應,子容器定高。
由於height:auto
時,計算高度值的依賴方向是從外往內。
自適應:爲什麼在這倆方案裏不允許出現父容器或子容器自適應於外層呢?
由於對於height來講,它的百分比值是乘以包含塊的height,但padding-top
/padding-bottom
/margin-top
/margin-bottom
的百分比值是乘以包含塊的width,而非咱們但願的height。
溢出:
* 父容器上下等padding時,父容器定高時,子容器溢出padding-edge的部分會被截斷。
* 子容器上下等margin時,父容器自適應於內部,父容器只會被撐高,永遠沒法被截斷。
* 其餘情形,截斷都沒有什麼意義
在子容器是<img>
標籤時,能夠直接使用background來替代它。也能夠算得上一種方案。
.inner { background-image: url("..."); background-position: 50% 50%;/*注,火狐不支持background-position-y的屬性設置*/ }
說明:
自適應:沒法自適應於外部容器,CSS2.1階段,background沒法相對於容器伸縮。
溢出:背景溢出的情形,直接會被截斷。
其餘:你甚至能夠把inner的標籤省掉,直接把背景放到outer之上
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其餘 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自適應於內部 | 自適應於外部 | 定高 | 自適應於內部 | 自適應於外部 | 撐高 | 被截斷 | 不需手工計算 | |
父容器line-height=height | √* | × | √ | × | × | √ | √ | √ | √ | × | √ |
子容器所在的line-box的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/
說明:
兼容性:沒有涉及relative和absolute定位,佈局時相對無痛。
兼容性:這個方案是IE6\7不支持的,緣由不詳(只知道inline-block
和vertical-align
的標準誕生於IE8以後),也沒有時間研究。2014年了,有點追求好嗎。
自適應:子容器能夠輕鬆作到自適應於內部、外部或者定高,但在這個方案裏,父容器必須定高,由於line-height
的百分比單位是相對font-size
來講的。
溢出:子容器溢出時會變成頂對齊,這是由於,line-box 的高度跟內部最高的 inline-box 相等,於是line-box 能夠被撐高,從上往下排一個個排列下來,從而失去了居中的效果。換句話說,子元素溢出時,父容器能夠自適應於內部。
其餘:line-height
和font-size
是一個能夠繼承的屬性,在這種方案裏面,必然會致使line-height
、font-size
被繼承,所以在須要排版子容器時,須要複寫line-height
、font-size
。
對上面的方法不兼容IE6\7且不能作到父容器自適應的方面,能夠這樣改進:
:before
/:after
僞元素自制一個文本節點、或<span>
或任意一個inline級別的標籤、或者一個1*1的圖片。inline-box
元素,而後設置height:100%
便可。vertical-align:middle
,讓它們的中心線對齊于于父容器的middle-line,就能作到垂直居中。http://jsfiddle.net/humphry/86dsC/21/
如今這個佈局能夠自動生成,詳見@林小志的css小工具:圖片垂直居中span。
(若是須要水平居中,那麼這個額外的節點,須要移去自身所佔的距離,通常使用margin-left:-1px
或margin-right:-1px
,取決於鉤子在子容器的哪一邊。)
說明:
兼容性:沒有涉及relative和absolute定位,佈局時相對無痛。
兼容性:inline-box標籤之間的任意數量的空白符:ASCII 空格 ( 
)、ASCII 製表符 (	
)、ASCII 換頁符 (
)、零寬度空格 (​
) 會被瀏覽器解析成一個空格,形成間隙。須要經過改變HTML結構/使用負margin等來去掉這個間隙。
兼容性:這個方案有必定hack量,去掉inline-box的空格間隙是一部分,display:inline-block
的IE6\7 hack是另外一部分。
自適應:父容器能夠自適應於外部了,由於這裏不須要在任何地方知道父容器的高度。
溢出:子容器溢出時會變成頂對齊,緣由同上。
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其餘 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自適應於內部 | 自適應於外部 | 定高 | 自適應於內部 | 自適應於外部 | 撐高 | 被截斷 | 不需手工計算 | |
父容器display:table-cell,子容器vertical-align | √ | × | √ | × | × | √ | √ | √ | √ | × | √ |
子容器被table、tr、td包裹 | √ | √ | √ | √* | √* | √ | √ | √ | √ | × | √ |
這個方案依然是用到vertical-align:middle
,只不過須要放到做爲display:table-cell
的元素之上。
http://jsfiddle.net/humphry/7AMF9/2/
這個佈局也能夠自動化生成:見@林小志的css小工具:圖片垂直居中 table cell
說明:
兼容性:IE6/7不兼容display:table-cell
。
自適應:子容器沒法自適應於父容器,高度沒法使用百分比單位,由於根據渲染規則,display:table-cell
的元素的包含塊是它父級的display:table
的元素。
溢出:父元素就算給定高度,設置overflow,也不會致使溢出隱藏;在子元素溢出的時候,父容器不能保有自身設置的高度,直接會被撐高。
其餘:display:tabel-cell自己讓不少屬性無效。
爲了可讓子容器有百分比高度,咱們能夠直接構建一個表結構出來:
http://jsfiddle.net/humphry/Ns4RK/8/
說明:
兼容性:這是一個全兼容的方案。
自適應:如今「父級」的自適應要求均可以獲得知足,只不過這裏的「父級」指的是包在最外層的table
。
溢出:父元素就算給定高度,設置overflow,也不會致使溢出隱藏。
其餘:文檔結構變複雜了,語義被拋棄了。
其餘:display:tabel-cell自己讓不少屬性無效。
其餘:能夠把這個方案裏的<table>
換成display:table
的其餘元素,tr、td亦然:
http://jsfiddle.net/humphry/KxKc8/
我的以爲……徒增煩惱爾。
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其餘 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自適應於內部 | 自適應於外部 | 定高 | 自適應於內部 | 自適應於外部 | 撐高 | 被截斷 | 不需手工計算 | |
子容器絕對定位,top:50%,負margin | √ | √ | √ | √* | √ | √ | × | × | × | √ | × |
子容器絕對定位,top:0,bottom:0,margin:auto | √ | × | √ | √* | √ | √ | × | √ | × | √ | √ |
.outer{ position: relative; } .inner{ position: absolute; top: 50%; height: 20px; margin: -10px; }
這是互聯網上能找到的最多的關於垂直居中的方法。咱們不相信瀏覽器,使用手算,將子元素挪去自身高度的50%。
說明:
兼容性:子元素和父元素都須要設置position
,這就意味着IE6\7下面的數十個友情附贈的美好bug。
自適應:子元素必須定高,不定高算不出來負margin。不能夠是百分比高度單位,由於margin-top
的百分比,是相對其包含塊的寬度而言的。
自適應:父容器能夠自適應於內部,只不過不是這個子元素,而是父容器內部其餘的元素。子元素對外層高度、寬度塌陷,不能撐寬/撐高父容器了。
溢出:這個方案也能夠支持子元素高度溢出的情形。
其餘:須要手動計算子元素1/2的高度是多少。
.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-top
和margin-bottom
是能夠根據上式算出的,原理相似於水平居中。
說明:
兼容性:這個方案僅僅支持IE8+。IE6和IE7因爲對同時定義top
、bottom
屬性的樣式解析與 css2.1 不一致,不支持這種定位方式。
自適應:父容器能夠自適應於內部,只不過不是這個子元素,而是父容器內部其餘的元素。緣由同上。
自適應:這個方案須要子容器有一個固定的高,或百分比自適應於外部。它的高度不能是height:auto
,由於這樣會使得上面的算式裏auto出如今三個地方,瀏覽器沒法計算出相應margin
值。
溢出:這個方案也能夠支持子元素高度溢出的情形。
其餘:徹底不用算,耶!
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其餘 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自適應於內部 | 自適應於外部 | 定高 | 自適應於內部 | 自適應於外部 | 撐高 | 被截斷 | 不需手工計算 | |
子容器絕對定位,top:50%,translateY(-50%) | × | × | √ | √* | √ | √ | √ | √ | × | √ | √ |
backgournd代圖片backgournd-size | × | × | √ | √ | √ | √ | √* | √ | × | √ | √ |
flexbox | × | × |
.outer{ position: relative; } .inner{ position: absolute; top: 50%; transform: translateY(-50%);}
原理同上,僅僅是僅僅是用translate
替換了負margin
,由於translate
的百分比偏移量是容器自己的。
說明:
兼容性:ie9+(但,從好處來說,其實這個兼容性已經徹底不須要考慮IE6~8的相對/絕對佈局bug了)
自適應:子元素能夠不指定高度,也能夠相對父級高寬作百分比設置,也包括定寬,很是靈活
自適應:父容器能夠自適應於內部,只不過不是這個子元素,而是父容器內部其餘的元素。緣由同上。
溢出:支持子元素溢出隱藏,或者溢出顯示。
其餘:你會讓代碼陷入一個前綴的海洋……
.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%); }
.inner{ background-image: url("...") ; background-size: cover ; height: 100% ; }
說明:
兼容性:只能是IE9+和現代瀏覽器
自適應:背景能夠任意自適應於外部容器,或者定高寬。也可讓子容器自適應於內部內容,背景自適應於子容器。
溢出:支持背景溢出隱藏,但沒法溢出顯示。好消息是,可使用background-clip
指定背景從哪裏消失。
其餘:你甚至能夠把.inner
的標籤省掉,直接把背景放到.outer
之上
// TBD // 很抱歉,因爲對flexbox沒有深刻的瞭解,我尚未試驗出flexbox在子元素溢出時也能保持居中的解決方案……最好的結果是子元素被拉伸(= =)。有人有過實例嗎?
說明:
兼容性:只能是IE9+和現代瀏覽器
其餘:兼容性是我目前已知的東西……