css居父容器下,整理:子容器垂直居中于父容器的方案
本文在evernote里有備份。如果evernote的閱讀區域嫌窄了,那么可以把這個鏈接拖入書簽并點擊javascript:jQuery("#container").width(980);
本文從這個回答整理而來。對于當今出現的一些CSS垂直居中的方案,這篇文章將會系統地審視它們,從實用角度進行評估。
不羅嗦,先上圖:
考量需求及難度
為避免混淆,本文中所說的父容器和子容器都不是相對的,而對應著如下文檔結構里面的.outer和.inner容器:
...
...
我們從如下角度來評估:
父容器/子容器的高度是否可變
是否需要手工計算
子元素溢出時父元素是截斷、被撐高還是保留滾動條
當然,還有兼容性
高度相關
代碼
效果
height:100px;
定高
height:auto
不定高,自適應于自身的content-box
height:50%
不定高,自適應于包含塊
出現了 3(定高/自適應于外部/自適應于內部) ^ 2 (父容器/子容器) =9 種情形,搭配見下:
父容器
子容器
難度
解(tu)說(cao)
定高
定高
簡單
快速開發時就是這樣
定高
自適應于內部
稍難
常見的需求
定高
自適應于外部
簡單
手工算一算就好了
自適應于內部
定高
簡單
變相定高,高度放在內層,方便解耦
自適應于內部
自適應于內部
稍難
留白固定,罕見的需求
自適應于內部
自適應于外部
WTF
折騰出這種需求,不覺得害臊嗎
自適應于外部
定高
困難
適配所有屏幕的slideshow
自適應于外部
自適應于內部
困難
普適性更高的slideshow
自適應于外部
自適應于外部
稍難
一個模塊(或大小不定的頭像),出現在大小不定的位置
溢出相關
子容器溢出代表子容器高度大于父容器高度的情形。
子容器溢出時,被父容器截斷。父容器overflow:hidden。
子容器溢出時,把父容器撐高。父容器height:auto;overflow:visible或display:table-cell等等。
子容器溢出時,父容器出現滾動條。父容器overflow:scroll或overflow:auto
很顯然,子容器溢出時,被父容器截斷的情形無法和父容器自適應于子容器共存。
兼容性
IE6、IE7:老而不死的瀏覽器,瀏覽器尚未統一、IE一家獨大之時的遺毒,一大堆bug等著你。
IE8:IE8起全面支持CSS2.1,剩下一些稍微少坑爹那么一點點的bug。
IE9。尷尬的產物,微軟第一次搭上CSS3的末班車。
IE10+與其他現代瀏覽器(終于可以和其他瀏覽器并列了……IE10淚目)。
4、3、2、1的兼容難度是一步步變難,兼容到4、3、2、1所對應的代碼量/工作量是100%、102%、120%、300%的關系。
在這里僅僅考量IE6/7,IE8的無bug實現的兼容性。IE9+的兼容性,對于文中提到的所有方案都是可行的。
其他
是否需要手動計算/需要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 ; }
說明:
需求:父子都需要自適應于內部的解決方案里,是把留白的高度固定,這種需求其實很少見。
可缺省: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時,父容器自適應于內部,父容器只會被撐高,永遠無法被截斷。
* 其他情形,截斷都沒有什么意義
1.3. background代圖片background-position
在子容器是標簽時,可以直接使用background來替代它。也可以算得上一種方案。
.inner { background-image: url("...");
background-position: 50% 50%;/*注,火狐不支持background-position-y的屬性設置*/ }
說明:
自適應:無法自適應于外部容器,CSS2.1階段,background無法相對于容器伸縮。
溢出:背景溢出的情形,直接會被截斷。
其他:你甚至可以把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:
使用font-size:0:
說明:
兼容性:沒有涉及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。
2.2 子容器所在的line-box的line-height=父容器的height
對上面的方法不兼容IE6\7且不能做到父容器自適應的方面,可以這樣改進:
把子容器當成行內元素呈遞
構建一個行內級別的鉤子元素,緊挨著子容器,以使用:before/:after偽元素自制一個文本節點、或或任意一個inline級別的標簽、或者一個1*1的圖片。
讓鉤子元素撐滿容器高度,這意味著它需要成為inline-box元素,然后設置height:100%即可。
現在,子容器所在的 line-box 的 line-height = 父容器的 height。
最后,給子容器和鉤子元素設置vertical-align:middle,讓它們的中心線對齊于于父容器的middle-line,就能做到垂直居中。
現在這個布局可以自動生成,詳見@林小志的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是另一部分。
自適應:父容器可以自適應于外部了,因為這里不需要在任何地方知道父容器的高度。
溢出:子容器溢出時會變成頂對齊,原因同上。
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的元素之上。
說明:
兼容性:IE6/7不兼容display:table-cell。
自適應:子容器無法自適應于父容器,高度無法使用百分比單位,因為根據渲染規則,display:table-cell的元素的包含塊是它父級的display:table的元素。
溢出:父元素就算給定高度,設置overflow,也不會導致溢出隱藏;在子元素溢出的時候,父容器不能保有自身設置的高度,直接會被撐高。
其他:display:tabel-cell本身讓很多屬性無效。
3.2. 子容器被table、tr、td包裹
為了可以讓子容器有百分比高度,我們可以直接構建一個表結構出來:
說明:
兼容性:這是一個全兼容的方案。
自適應:現在“父級”的自適應要求都可以得到滿足,只不過這里的“父級”指的是包在最外層的table。
溢出:父元素就算給定高度,設置overflow,也不會導致溢出隱藏。
其他:文檔結構變復雜了,語義被拋棄了。
其他:display:tabel-cell本身讓很多屬性無效。
其他:可以把這個方案里的
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%。
說明:
兼容性:子元素和父元素都需要設置position,這就意味著IE6\7下面的數十個友情附贈的美好bug。
自適應:子元素必須定高,不定高算不出來負margin。不可以是百分比高度單位,因為margin-top的百分比,是相對其包含塊的寬度而言的。
自適應:父容器可以自適應于內部,只不過不是這個子元素,而是父容器內部其他的元素。子元素對外層高度、寬度塌陷,不能撐寬/撐高父容器了。
溢出:這個方案也可以支持子元素高度溢出的情形。
其他:需要手動計算子元素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-top和margin-bottom是可以根據上式算出的,原理類似于水平居中。
說明:
兼容性:這個方案僅僅支持IE8+。IE6和IE7由于對同時定義top、bottom屬性的樣式解析與 css2.1 不一致,不支持這種定位方式。
自適應:父容器可以自適應于內部,只不過不是這個子元素,而是父容器內部其他的元素。原因同上。
自適應:這個方案需要子容器有一個固定的高,或百分比自適應于外部。它的高度不能是height:auto,因為這樣會使得上面的算式里auto出現在三個地方,瀏覽器無法計算出相應margin值。
溢出:這個方案也可以支持子元素高度溢出的情形。
其他:完全不用算,耶!
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的百分比偏移量是容器本身的。
說明:
兼容性: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%);
}
5.2 backgournd代圖片,backgournd-size
.inner{ background-image: url("...") ; background-size: cover ; height: 100% ; }
說明:
兼容性:只能是IE9+和現代瀏覽器
自適應:背景可以任意自適應于外部容器,或者定高寬。也可以讓子容器自適應于內部內容,背景自適應于子容器。
溢出:支持背景溢出隱藏,但無法溢出顯示。好消息是,可以使用background-clip指定背景從哪里消失。
其他:你甚至可以把.inner的標簽省掉,直接把背景放到.outer之上
5.3 flexbox
// TBD
// 很抱歉,由于對flexbox沒有深入的了解,我還沒有試驗出flexbox在子元素溢出時也能保持居中的解決方案……最好的結果是子元素被拉伸(= =)。有人有過實例嗎?
說明:
兼容性:只能是IE9+和現代瀏覽器
其他:兼容性是我目前已知的東西……
總結
以上是生活随笔為你收集整理的css居父容器下,整理:子容器垂直居中于父容器的方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信小程序直播自己的服务器,使用微信小程
- 下一篇: 考研预报名一直显示服务器错误,2021考