子容器小于父容器的情况,我知道如何垂直居中。
但是当子容器的高度超过父容器的时候,我如何让子容器相对于父容器垂直居中?
PS: 补充一句,子容器宽度是百分比,动态的。父容器的宽度是100%。
效果如图, 让红色部分相对于绿色部分垂直居中:
认证高级PHP讲师
更新:出文章啦,還有表格參考喲http://blog.segmentfault.com/humphry/1190000000381042
相信每一個前端都或多或少總結過居中吧。這裏是居中的最麻煩最不好處理的一個情形:子元素溢出。
我們在解決這個問題之前,先回顧一下,子元素不溢出父元素的時候,我們常見的CSS居中方案。以及為何在子元素溢出的時候,問題變得棘手。
首先我們確定計算流程:
H外 = H内 + 2 * H补 ;
子容器溢不溢出,這個流程都不會變。
我們可以看到,要做到計算,我們必須拿到兩個值,一個是H外,一個是H內。
在到了需要JS計算的時刻,這些值都可以通過CSSOM來取得,而使用jQuery具體的做法如@怡紅公子所說,就不多說了。
而CSS布局的核心在於,在父容器高寬不固定的時候,如何讓瀏覽器幫我們計算?
我們必須保證瀏覽器解析到相應的樣式時,能夠拿到H外和H內。
這個方案已經濫了。
.outer{ position: relative; overflow: hidden ; } .inner{ position : absolute; top: 50%; height: 20px; margin: -10px; }
我們不相信瀏覽器,使用手算,將子元素挪去自身高度的50%。這個方案也可以支持子元素高度溢出的情形。
優點:
缺陷:
position:absolute;
.outer { height: 300px; line-height: 300px; }
如果內容隻有一行文字,很簡單。line-height作用於line-box,把line-box撐到和父容器一樣高,文字節點默認對齊於line-box的baseline。
內部容器,則需要作為行內元素呈遞:
.inner { display: inline-block; }
:before
這個方案是可以改進,以適應溢出情形的,在中間增加一層足夠高(你來定義一個高度,比如10000px)的容器,用負margin方法垂直居中於外層,然後用line-height=height方法讓內部居中於中間層。實現比較複雜,也結合了兩種方案的優點,和……缺點。個人覺得還不如直接使用負margin方案來得爽快些。
.outer{ position: relative; height: 100px ; overflow: hidden ; } .inner{ margin-top : auto; margin-bottom : auto; position : absolute; 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是可以根據上式算出的,原理類似於水平居中。看到沒有,這個包含塊高度算式就複現了我們需要的計算過程。
子元素高度溢出父容器時,這個方案依然可行。
這是CSS2.1範疇內適用麵最廣的垂直居中方式。能夠涵蓋溢出的情形。
見圖片垂直居中tabel_cell
display:tabel-cell
這個方案不符合樓主的要求,就不多說了。
見居中百分比寬高的元素
.inner{ position : absolute; top: 50%; transform: translate(-50%, -50%); }
這裏其實是負margin的改版,僅僅是用translate替換了負margin,因為translate是針對容器本身的。
優點
缺點
.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% ; display: block ; }
如果是一個圖片,可以用background-size:cover或background-size:contain來做到簡單的居中。若不需要拉伸,也可以使用background-position-y:center 來做。
background-size:cover
background-size:contain
background-position-y:center
為何不把這個方案放在CSS2.1中呢,因為隻有在CSS3中,背景才可以相對容器變化大小,比如等於容器高度:
.inner{ background-size: auto 100% ; }
或者等於容器寬度
.inner{ background-size: 100% auto ; }
缺點:
很抱歉,我還沒有試驗出flexbox在子元素溢出時也能保持居中的解決方案……最好的結果是子元素被拉伸(= =#)。有人有過實例嗎?
其實在這裏討論的居中方案暗含了一個條件:父容器overflow:hidden,父容器本身就有BFC……其實前端排版中的垂直居中還不止於此,父容器可以被撐高是另外一種情形,不過偏離LZ的問題太遠,這裏不再多說。
overflow:hidden
如果超過部分上下正好是一樣的話,直接用line-height: 子容器高度(單行情況)或者display:inline-table;vertical-algin:middle;(對應其它情況)保證在子容器居中就可以保證相對於父容器居中了吧。另外,如果不兼容過時的瀏覽器的話,可以試試CSS3的一些東西,做垂直居中還是非常簡單方便的:http://zh.learnlayout.com/flexbox.html
line-height: 子容器高度
display:inline-table;vertical-algin:middle;
如果超過部分上下不一樣的話我暫時隻能想到用JavaScript計算差值然後給margin的方法呢。(示例是jQuery的語法,語義版,father是紅色方框,子容器的內容需要再包括在一個標簽內):
margin
father
var father = $('.father'), child = father.children(), grandfather = father.parent(); var marginTop = grandfather.offset().top - father.offset().top + (grandfather.height() - child.height())/2; child.css('margin-top', marginTop+'px');
額,之前好像沒看清楚題目,謝謝 @Humphry 提醒。如果隻是容器要垂直居中的話可以用JavaScript計算兩者高度相減除以2,並給與margin-top,或者直接使用CSS3的calc()計算margin-top的值就好了,關於這個你可以看看這個:http://www.qianduan.net/calc-at-at-at-page-intelligent-layout.html
margin-top
calc()
var father = $('.father'), child = father.children(); var marginTop = (father.height() - child.height())/2; child.css('margin-top', marginTop+'px');
這個實現比較簡單,希望能解答你的問題,我是這麼理解的。
http://jsfiddle.net/BNnXN/
更新:出文章啦,還有表格參考喲http://blog.segmentfault.com/humphry/1190000000381042
相信每一個前端都或多或少總結過居中吧。這裏是居中的最麻煩最不好處理的一個情形:子元素溢出。
我們在解決這個問題之前,先回顧一下,子元素不溢出父元素的時候,我們常見的CSS居中方案。以及為何在子元素溢出的時候,問題變得棘手。
思路
首先我們確定計算流程:
子容器溢不溢出,這個流程都不會變。
我們可以看到,要做到計算,我們必須拿到兩個值,一個是H外,一個是H內。
在到了需要JS計算的時刻,這些值都可以通過CSSOM來取得,而使用jQuery具體的做法如@怡紅公子所說,就不多說了。
而CSS布局的核心在於,在父容器高寬不固定的時候,如何讓瀏覽器幫我們計算?
我們必須保證瀏覽器解析到相應的樣式時,能夠拿到H外和H內。
CSS2.1
子元素負margin方案
這個方案已經濫了。
我們不相信瀏覽器,使用手算,將子元素挪去自身高度的50%。這個方案也可以支持子元素高度溢出的情形。
優點:
缺陷:
position:absolute;
,子元素對外層高度、寬度塌陷,不能撐寬父容器了。父容器 line-height = height 單行方案
如果內容隻有一行文字,很簡單。line-height作用於line-box,把line-box撐到和父容器一樣高,文字節點默認對齊於line-box的baseline。
內部容器,則需要作為行內元素呈遞:
優點:
缺陷:
:before
偽元素。具體方案見CSS小工具,同時inline-box之間的空格間隙需要被考慮在內,見去除inline-block元素間間距的N種方法。這個方案是可以改進,以適應溢出情形的,在中間增加一層足夠高(你來定義一個高度,比如10000px)的容器,用負margin方法垂直居中於外層,然後用line-height=height方法讓內部居中於中間層。實現比較複雜,也結合了兩種方案的優點,和……缺點。個人覺得還不如直接使用負margin方案來得爽快些。
子元素margin:auto方案
這個的原理寫在CSS2.1中:
‘top’ ‘margin-top’ ‘border-top-width’ ‘padding-top’ ‘height’ ‘padding-bottom’ ‘border-bottom-width’ ‘margin-bottom’ ‘bottom’ = 包含塊的高度
在其他值不是auto的時候,margin-top和margin-bottom是可以根據上式算出的,原理類似於水平居中。看到沒有,這個包含塊高度算式就複現了我們需要的計算過程。
子元素高度溢出父容器時,這個方案依然可行。
優點:
缺陷:
position:absolute;
,子元素對外層高度、寬度塌陷,不能撐寬父容器了。這是CSS2.1範疇內適用麵最廣的垂直居中方式。能夠涵蓋溢出的情形。
display:table-cell vertical-align方案
見圖片垂直居中tabel_cell
優點:
缺陷:
display:tabel-cell
本身讓很多屬性無效display:tabel-cell
IE6和IE7不支持這個方案不符合樓主的要求,就不多說了。
CSS3
-50% 的 translate方案
見居中百分比寬高的元素
這裏其實是負margin的改版,僅僅是用translate替換了負margin,因為translate是針對容器本身的。
優點
缺點
background方案
如果是一個圖片,可以用
background-size:cover
或background-size:contain
來做到簡單的居中。若不需要拉伸,也可以使用background-position-y:center
來做。為何不把這個方案放在CSS2.1中呢,因為隻有在CSS3中,背景才可以相對容器變化大小,比如等於容器高度:
或者等於容器寬度
優點:
缺點:
flexbox方案
很抱歉,我還沒有試驗出flexbox在子元素溢出時也能保持居中的解決方案……最好的結果是子元素被拉伸(= =#)。有人有過實例嗎?
其實在這裏討論的居中方案暗含了一個條件:父容器
overflow:hidden
,父容器本身就有BFC……其實前端排版中的垂直居中還不止於此,父容器可以被撐高是另外一種情形,不過偏離LZ的問題太遠,這裏不再多說。如果超過部分上下正好是一樣的話,直接用
line-height: 子容器高度
(單行情況)或者display:inline-table;vertical-algin:middle;
(對應其它情況)保證在子容器居中就可以保證相對於父容器居中了吧。另外,如果不兼容過時的瀏覽器的話,可以試試CSS3的一些東西,做垂直居中還是非常簡單方便的:http://zh.learnlayout.com/flexbox.html如果超過部分上下不一樣的話我暫時隻能想到用JavaScript計算差值然後給
margin
的方法呢。(示例是jQuery的語法,語義版,father
是紅色方框,子容器的內容需要再包括在一個標簽內):額,之前好像沒看清楚題目,謝謝 @Humphry 提醒。如果隻是容器要垂直居中的話可以用JavaScript計算兩者高度相減除以2,並給與
margin-top
,或者直接使用CSS3的calc()
計算margin-top
的值就好了,關於這個你可以看看這個:http://www.qianduan.net/calc-at-at-at-page-intelligent-layout.html這個實現比較簡單,希望能解答你的問題,我是這麼理解的。
http://jsfiddle.net/BNnXN/