首页 > 子容器超过父容器如何垂直居中

子容器超过父容器如何垂直居中

子容器小于父容器的情况,我知道如何垂直居中。

但是当子容器的高度超过父容器的时候,我如何让子容器相对于父容器垂直居中?

PS: 补充一句,子容器宽度是百分比,动态的。父容器的宽度是100%。

效果如图, 让红色部分相对于绿色部分垂直居中:


这个实现比较简单,希望能解答你的问题,我是这么理解的。

http://jsfiddle.net/BNnXN/


更新:出文章啦,还有表格参考哟http://blog..com/humphry/1190000000381042


相信每一个前端都或多或少总结过居中吧。这里是居中的最麻烦最不好处理的一个情形:子元素溢出。

我们在解决这个问题之前,先回顾一下,子元素不溢出父元素的时候,我们常见的CSS居中方案。以及为何在子元素溢出的时候,问题变得棘手。

思路

首先我们确定计算流程:

H外 = H内 + 2 * H补 ;

子容器溢不溢出,这个流程都不会变。

我们可以看到,要做到计算,我们必须拿到两个值,一个是H外,一个是H内。

在到了需要JS计算的时刻,这些值都可以通过CSSOM来取得,而使用jQuery具体的做法如@怡红公子所说,就不多说了。

而CSS布局的核心在于,在父容器高宽不固定的时候,如何让浏览器帮我们计算?

我们必须保证浏览器解析到相应的样式时,能够拿到H外和H内。

CSS2.1

子元素负margin方案

这个方案已经滥了。

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

我们不相信浏览器,使用手算,将子元素挪去自身高度的50%。这个方案也可以支持子元素高度溢出的情形。

优点:

缺陷:

父容器 line-height = height 单行方案

.outer {
    height: 300px;
    line-height: 300px;
}

如果内容只有一行文字,很简单。line-height作用于line-box,把line-box撑到和父容器一样高,文字节点默认对齐于line-box的baseline。

内部容器,则需要作为行内元素呈递:

.inner { display: inline-block; }

优点:

缺陷:

这个方案是可以改进,以适应溢出情形的,在中间增加一层足够高(你来定义一个高度,比如10000px)的容器,用负margin方法垂直居中于外层,然后用line-height=height方法让内部居中于中间层。实现比较复杂,也结合了两种方案的优点,和……缺点。个人觉得还不如直接使用负margin方案来得爽快些。

子元素margin:auto方案

.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范畴内适用面最广的垂直居中方式。能够涵盖溢出的情形。

display:table-cell + vertical-align方案

见图片垂直居中tabel_cell

优点:

缺陷:

这个方案不符合楼主的要求,就不多说了。


CSS3

-50% 的 translate方案

见居中百分比宽高的元素

.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%);
}

background方案

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

如果是一个图片,可以用background-size:coverbackground-size:contain来做到简单的居中。若不需要拉伸,也可以使用background-position-y:center 来做。

为何不把这个方案放在CSS2.1中呢,因为只有在CSS3中,背景才可以相对容器变化大小,比如等于容器高度:

.inner{ background-size: auto 100% ; }

或者等于容器宽度

.inner{ background-size: 100% auto ; }

优点:

缺点:

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是红色方框,子容器的内容需要再包括在一个标签内):

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

var father = $('.father'), child = father.children();
var marginTop = (father.height() - child.height())/2;
child.css('margin-top', marginTop+'px');
【热门文章】
【热门文章】