子容器小于父容器的情况,我知道如何垂直居中。
但是当子容器的高度超过父容器的时候,我如何让子容器相对于父容器垂直居中?
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/