本文在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:visible
或display:table-cell
等等。overflow:scroll
或overflow:auto
很显然,子容器溢出时,被父容器截断的情形没法和父容器自适应于子容器共存。浏览器
四、三、二、1的兼容难度是一步步变难,兼容到四、三、二、1所对应的代码量/工做量是100%、102%、120%、300%的关系。ide
在这里仅仅考量IE6/7,IE8的无bug实现的兼容性。IE9+的兼容性,对于文中提到的全部方案都是可行的。wordpress
若是须要手动计算,若界面进行重构,而居中的需求不变,就须要从新计算。比较费时费事。布局也相对不够灵活。
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 |
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其余 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自适应于内部 | 自适应于外部 | 定高 | 自适应于内部 | 自适应于外部 | 撑高 | 被截断 | 不需手工计算 | |
父容器上下等padding | √ | √ | √ | √* | × | √ | √* | × | √ | √* | × |
子容器上下等margin | √ | √ | √ | √* | × | √ | √* | × | √ | × | × |
background代图片background-position | √ | √ | √ | √ | √ | √ | × | × | × | √ | √ |
最基础的方案就是这样,手工算好每个容器的高度和补白/位移须要的内容,简单粗暴:
/*父子均定高,父容器上下等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时,父容器自适应于内部,父容器只会被撑高,永远没法被截断。
* 其余情形,截断都没有什么意义
在子容器是<img>
标签时,能够直接使用background来替代它。也能够算得上一种方案。
.inner { background-image: url("..."); background-position: 50% 50%;/*注,火狐不支持background-position-y的属性设置*/ }
说明:
自适应:没法自适应于外部容器,CSS2.1阶段,background没法相对于容器伸缩。
溢出:背景溢出的情形,直接会被截断。
其余:你甚至能够把inner的标签省掉,直接把背景放到outer之上
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其余 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自适应于内部 | 自适应于外部 | 定高 | 自适应于内部 | 自适应于外部 | 撑高 | 被截断 | 不需手工计算 | |
父容器line-height=height | √* | × | √ | × | × | √ | √ | √ | √ | × | √ |
子容器所在的line-box的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/
说明:
兼容性:没有涉及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
。
对上面的方法不兼容IE6\7且不能作到父容器自适应的方面,能够这样改进:
:before
/:after
伪元素自制一个文本节点、或<span>
或任意一个inline级别的标签、或者一个1*1的图片。inline-box
元素,而后设置height:100%
便可。vertical-align:middle
,让它们的中心线对齐于于父容器的middle-line,就能作到垂直居中。http://jsfiddle.net/humphry/86dsC/21/
如今这个布局能够自动生成,详见@林小志的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是另外一部分。
自适应:父容器能够自适应于外部了,由于这里不须要在任何地方知道父容器的高度。
溢出:子容器溢出时会变成顶对齐,缘由同上。
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其余 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自适应于内部 | 自适应于外部 | 定高 | 自适应于内部 | 自适应于外部 | 撑高 | 被截断 | 不需手工计算 | |
父容器display:table-cell,子容器vertical-align | √ | × | √ | × | × | √ | √ | √ | √ | × | √ |
子容器被table、tr、td包裹 | √ | √ | √ | √* | √* | √ | √ | √ | √ | × | √ |
这个方案依然是用到vertical-align:middle
,只不过须要放到做为display:table-cell
的元素之上。
http://jsfiddle.net/humphry/7AMF9/2/
这个布局也能够自动化生成:见@林小志的css小工具:图片垂直居中 table cell
说明:
兼容性:IE6/7不兼容display:table-cell
。
自适应:子容器没法自适应于父容器,高度没法使用百分比单位,由于根据渲染规则,display:table-cell
的元素的包含块是它父级的display:table
的元素。
溢出:父元素就算给定高度,设置overflow,也不会致使溢出隐藏;在子元素溢出的时候,父容器不能保有自身设置的高度,直接会被撑高。
其余:display:tabel-cell自己让不少属性无效。
为了可让子容器有百分比高度,咱们能够直接构建一个表结构出来:
http://jsfiddle.net/humphry/Ns4RK/8/
说明:
兼容性:这是一个全兼容的方案。
自适应:如今“父级”的自适应要求均可以获得知足,只不过这里的“父级”指的是包在最外层的table
。
溢出:父元素就算给定高度,设置overflow,也不会致使溢出隐藏。
其余:文档结构变复杂了,语义被抛弃了。
其余:display:tabel-cell自己让不少属性无效。
其余:能够把这个方案里的<table>
换成display:table
的其余元素,tr、td亦然:
http://jsfiddle.net/humphry/KxKc8/
我的以为……徒增烦恼尔。
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其余 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自适应于内部 | 自适应于外部 | 定高 | 自适应于内部 | 自适应于外部 | 撑高 | 被截断 | 不需手工计算 | |
子容器绝对定位,top:50%,负margin | √ | √ | √ | √* | √ | √ | × | × | × | √ | × |
子容器绝对定位,top:0,bottom:0,margin:auto | √ | × | √ | √* | √ | √ | × | √ | × | √ | √ |
.outer{ position: relative; } .inner{ position: absolute; top: 50%; height: 20px; margin: -10px; }
这是互联网上能找到的最多的关于垂直居中的方法。咱们不相信浏览器,使用手算,将子元素挪去自身高度的50%。
说明:
兼容性:子元素和父元素都须要设置position
,这就意味着IE6\7下面的数十个友情附赠的美好bug。
自适应:子元素必须定高,不定高算不出来负margin。不能够是百分比高度单位,由于margin-top
的百分比,是相对其包含块的宽度而言的。
自适应:父容器能够自适应于内部,只不过不是这个子元素,而是父容器内部其余的元素。子元素对外层高度、宽度塌陷,不能撑宽/撑高父容器了。
溢出:这个方案也能够支持子元素高度溢出的情形。
其余:须要手动计算子元素1/2的高度是多少。
.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
值。
溢出:这个方案也能够支持子元素高度溢出的情形。
其余:彻底不用算,耶!
方案 | 兼容性 | 父容器 | 子容器 | 子容器溢出 | 其余 | ||||||
---|---|---|---|---|---|---|---|---|---|---|---|
IE8 | IE6/7 | 定高 | 自适应于内部 | 自适应于外部 | 定高 | 自适应于内部 | 自适应于外部 | 撑高 | 被截断 | 不需手工计算 | |
子容器绝对定位,top:50%,translateY(-50%) | × | × | √ | √* | √ | √ | √ | √ | × | √ | √ |
backgournd代图片backgournd-size | × | × | √ | √ | √ | √ | √* | √ | × | √ | √ |
flexbox | × | × |
.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%); }
.inner{ background-image: url("...") ; background-size: cover ; height: 100% ; }
说明:
兼容性:只能是IE9+和现代浏览器
自适应:背景能够任意自适应于外部容器,或者定高宽。也可让子容器自适应于内部内容,背景自适应于子容器。
溢出:支持背景溢出隐藏,但没法溢出显示。好消息是,可使用background-clip
指定背景从哪里消失。
其余:你甚至能够把.inner
的标签省掉,直接把背景放到.outer
之上
// TBD // 很抱歉,因为对flexbox没有深刻的了解,我尚未试验出flexbox在子元素溢出时也能保持居中的解决方案……最好的结果是子元素被拉伸(= =)。有人有过实例吗?
说明:
兼容性:只能是IE9+和现代浏览器
其余:兼容性是我目前已知的东西……