整理:子容器垂直居中于父容器的方案

本文在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:visibledisplay:table-cell等等。
  • 子容器溢出时,父容器出现滚动条。父容器overflow:scrolloverflow:auto

很显然,子容器溢出时,被父容器截断的情形没法和父容器自适应于子容器共存。浏览器

兼容性

  1. IE六、IE7:老而不死的浏览器,浏览器还没有统1、IE一家独大之时的遗毒,一大堆bug等着你。
  2. IE8:IE8起全面支持CSS2.1,剩下一些稍微少坑爹那么一点点的bug。
  3. IE9。尴尬的产物,微软第一次搭上CSS3的末班车。
  4. IE10+与其余现代浏览器(终于能够和其余浏览器并列了……IE10泪目)。

四、三、二、1的兼容难度是一步步变难,兼容到四、三、二、1所对应的代码量/工做量是100%、102%、120%、300%的关系。ide

在这里仅仅考量IE6/7,IE8的无bug实现的兼容性。IE9+的兼容性,对于文中提到的全部方案都是可行的。wordpress

其余

  1. 是否须要手动计算/须要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 ; }

说明:

  1. 需求:父子都须要自适应于内部的解决方案里,是把留白的高度固定,这种需求其实不多见。
  2. 可缺省:height:auto能够省去,这是默认值。
    对于块级元素,默认是height:auto;width:auto;
    width的auto值是自适应于这个元素的包含块的宽度,而height自适应于这个元素的content-box的高度

  3. 自适应:父子容器都可以自适应于内部;也能够父容器自适应,子容器定高。
    由于height:auto时,计算高度值的依赖方向是从外往内。

  4. 自适应:为什么在这俩方案里不允许出现父容器或子容器自适应于外层呢?
    由于对于height来讲,它的百分比值是乘以包含块的height,但padding-top/padding-bottom/margin-top/margin-bottom的百分比值是乘以包含块的width,而非咱们但愿的height。

  5. 溢出:

* 父容器上下等padding时,父容器定高时,子容器溢出padding-edge的部分会被截断。
* 子容器上下等margin时,父容器自适应于内部,父容器只会被撑高,永远没法被截断。
* 其余情形,截断都没有什么意义

1.3. background代图片background-position

在子容器是<img>标签时,能够直接使用background来替代它。也能够算得上一种方案。

.inner { background-image: url("...");
   background-position: 50% 50%;/*注,火狐不支持background-position-y的属性设置*/ }

说明:

  1. 自适应:没法自适应于外部容器,CSS2.1阶段,background没法相对于容器伸缩。

  2. 溢出:背景溢出的情形,直接会被截断。

  3. 其余:你甚至能够把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

http://jsfiddle.net/humphry/haaaM/

使用font-size:0

http://jsfiddle.net/humphry/7zCEm/

说明:

  1. 兼容性:没有涉及relative和absolute定位,布局时相对无痛。

  2. 兼容性:这个方案是IE6\7不支持的,缘由不详(只知道inline-blockvertical-align的标准诞生于IE8以后),也没有时间研究。2014年了,有点追求好吗。

  3. 自适应:子容器能够轻松作到自适应于内部、外部或者定高,但在这个方案里,父容器必须定高,由于line-height的百分比单位是相对font-size来讲的。

  4. 溢出:子容器溢出时会变成顶对齐,这是由于,line-box 的高度跟内部最高的 inline-box 相等,于是line-box 能够被撑高,从上往下排一个个排列下来,从而失去了居中的效果。换句话说,子元素溢出时,父容器能够自适应于内部。

  5. 其余:line-heightfont-size是一个能够继承的属性,在这种方案里面,必然会致使line-heightfont-size被继承,所以在须要排版子容器时,须要复写line-heightfont-size

2.2 子容器所在的line-box的line-height=父容器的height

对上面的方法不兼容IE6\7且不能作到父容器自适应的方面,能够这样改进:

  1. 把子容器当成行内元素呈递
  2. 构建一个行内级别的钩子元素,紧挨着子容器,以使用:before/:after伪元素自制一个文本节点、或<span>或任意一个inline级别的标签、或者一个1*1的图片。
  3. 让钩子元素撑满容器高度,这意味着它须要成为inline-box元素,而后设置height:100%便可。
  4. 如今,子容器所在的 line-box 的 line-height = 父容器的 height。
  5. 最后,给子容器和钩子元素设置vertical-align:middle,让它们的中心线对齐于于父容器的middle-line,就能作到垂直居中。

http://jsfiddle.net/humphry/86dsC/21/

如今这个布局能够自动生成,详见@林小志的css小工具:图片垂直居中span

(若是须要水平居中,那么这个额外的节点,须要移去自身所占的距离,通常使用margin-left:-1pxmargin-right:-1px,取决于钩子在子容器的哪一边。)

说明:

  1. 兼容性:没有涉及relative和absolute定位,布局时相对无痛。

  2. 兼容性:inline-box标签之间的任意数量的空白符:ASCII 空格 (&#x0020;)、ASCII 制表符 (&#x0009;)、ASCII 换页符 (&#x000C;)、零宽度空格 (&#x200B;) 会被浏览器解析成一个空格,形成间隙。须要经过改变HTML结构/使用负margin等来去掉这个间隙

  3. 兼容性:这个方案有必定hack量,去掉inline-box的空格间隙是一部分,display:inline-block的IE6\7 hack是另外一部分。

  4. 自适应:父容器能够自适应于外部了,由于这里不须要在任何地方知道父容器的高度。

  5. 溢出:子容器溢出时会变成顶对齐,缘由同上。

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的元素之上。

http://jsfiddle.net/humphry/7AMF9/2/

这个布局也能够自动化生成:见@林小志的css小工具:图片垂直居中 table cell

说明:

  1. 兼容性:IE6/7不兼容display:table-cell

  2. 自适应:子容器没法自适应于父容器,高度没法使用百分比单位,由于根据渲染规则,display:table-cell的元素的包含块是它父级的display:table的元素。

  3. 溢出:父元素就算给定高度,设置overflow,也不会致使溢出隐藏;在子元素溢出的时候,父容器不能保有自身设置的高度,直接会被撑高。

  4. 其余:display:tabel-cell自己让不少属性无效。

3.2. 子容器被table、tr、td包裹

为了可让子容器有百分比高度,咱们能够直接构建一个表结构出来:

http://jsfiddle.net/humphry/Ns4RK/8/

说明:

  1. 兼容性:这是一个全兼容的方案。

  2. 自适应:如今“父级”的自适应要求均可以获得知足,只不过这里的“父级”指的是包在最外层的table

  3. 溢出:父元素就算给定高度,设置overflow,也不会致使溢出隐藏。

  4. 其余:文档结构变复杂了,语义被抛弃了。

  5. 其余:display:tabel-cell自己让不少属性无效。

  6. 其余:能够把这个方案里的<table>换成display:table的其余元素,tr、td亦然:
    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%。

说明:

  1. 兼容性:子元素和父元素都须要设置position,这就意味着IE6\7下面的数十个友情附赠的美好bug。

  2. 自适应:子元素必须定高,不定高算不出来负margin。不能够是百分比高度单位,由于margin-top的百分比,是相对其包含块的宽度而言的。

  3. 自适应:父容器能够自适应于内部,只不过不是这个子元素,而是父容器内部其余的元素。子元素对外层高度、宽度塌陷,不能撑宽/撑高父容器了。

  4. 溢出:这个方案也能够支持子元素高度溢出的情形。

  5. 其余:须要手动计算子元素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-topmargin-bottom是能够根据上式算出的,原理相似于水平居中。

说明:

  1. 兼容性:这个方案仅仅支持IE8+。IE6和IE7因为对同时定义topbottom属性的样式解析与 css2.1 不一致,不支持这种定位方式。

  2. 自适应:父容器能够自适应于内部,只不过不是这个子元素,而是父容器内部其余的元素。缘由同上。

  3. 自适应:这个方案须要子容器有一个固定的高,或百分比自适应于外部。它的高度不能是height:auto,由于这样会使得上面的算式里auto出如今三个地方,浏览器没法计算出相应margin值。

  4. 溢出:这个方案也能够支持子元素高度溢出的情形。

  5. 其余:彻底不用算,耶!

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的百分比偏移量是容器自己的。

说明:

  1. 兼容性:ie9+(但,从好处来说,其实这个兼容性已经彻底不须要考虑IE6~8的相对/绝对布局bug了)

  2. 自适应:子元素能够不指定高度,也能够相对父级高宽作百分比设置,也包括定宽,很是灵活

  3. 自适应:父容器能够自适应于内部,只不过不是这个子元素,而是父容器内部其余的元素。缘由同上。

  4. 溢出:支持子元素溢出隐藏,或者溢出显示。

  5. 其余:你会让代码陷入一个前缀的海洋……

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

说明:

  1. 兼容性:只能是IE9+和现代浏览器

  2. 自适应:背景能够任意自适应于外部容器,或者定高宽。也可让子容器自适应于内部内容,背景自适应于子容器。

  3. 溢出:支持背景溢出隐藏,但没法溢出显示。好消息是,可使用background-clip指定背景从哪里消失。

  4. 其余:你甚至能够把.inner的标签省掉,直接把背景放到.outer之上

5.3 flexbox

// TBD
// 很抱歉,因为对flexbox没有深刻的了解,我尚未试验出flexbox在子元素溢出时也能保持居中的解决方案……最好的结果是子元素被拉伸(= =)。有人有过实例吗?

说明:

  1. 兼容性:只能是IE9+和现代浏览器

  2. 其余:兼容性是我目前已知的东西……


请输入图片描述
相关文章
相关标签/搜索