共计 7901 个字符,预计需要花费 20 分钟才能阅读完成。
我们都知道 margin:0 auto;
的样式能让元素水平居中,而 margin: auto;
却不能做到垂直居中……直到现在。但是,请注意!想让元素绝对居中,只需要声明元素高度,并且附加以下样式,就可以做到:
.absolute-center {
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
}
我并不是第一个发现这种方法的人(不过我还是敢把它叫做“完全居中”),它有可能是种非常普遍的技巧。但大多数介绍垂直居中的文章中并没有提到过这种方法。如果不是浏览这篇文章的评论,我甚至根本就不会发现这个办法。
上面那篇文章的评论栏中,simon 提供了一个 jsfiddle 的链接,其他的方法相比之下就相形见绌了。(priit 也在评论栏中提到了同样的方法)。深入研究了一番之后,我又用某些关键词找到了记载这种方法的三个网站:站点一、站点二、站点三。
以前从未用过这种方法的我想试试,看看这种”完全居中”的方法到底有多么神奇。好处:
- 跨浏览器,兼容性好(无需 hack,可兼顾 ie8~ie10)
- 无特殊标记,样式更精简
- 自适应布局,可以使用百分比和最大最小高宽等样式
- 居中时不考虑元素的 padding 值(也不需要使用 box-sizing 样式)
- 布局块可以自由调节大小
- img 的图像也可以使用
同时注意:
- 必须声明元素高度
- 推荐设置 overflow:auto; 样式避免元素溢出,显示不正常的问题
- 这种方法在 windows phone 上不起作用
浏览器支持:chrome、firefox、safari、mobile safari、ie8-10。“完全居中”经测试可以完美地应用在最新版本的 chrome、firefox、safari、mobile safari 中,甚至也可以运行在 ie8~ie10 上
在研究了规范和文档后,我总结出了“完全居中”的工作原理:
- 在普通文档流里,margin: auto; 的意思是设置元素的 margin-top 和 margin-bottom 为 0。w3.org if‘margin-top’, or‘margin-bottom’are‘auto’, their used value is 0.
- 设置了 position: absolute; 的元素会变成块元素,并脱离普通文档流。而文档的其余部分照常渲染,元素像是不在原来的位置一样。developer.mozilla.org …an element that is positioned absolutely is taken out of the flow and thus takes up no space
- 设置了 top: 0; left: 0; bottom: 0; right: 0; 样式的块元素会让浏览器为它包裹一层新的盒子,因此这个元素会填满它相对父元素的内部空间,这个相对父元素可以是是 body 标签,或者是一个设置了 position: relative; 样式的容器。developer.mozilla.org for absolutely positioned elements, the top, right, bottom, and left properties specify offsets from the edge of the element’s containing block (what the element is positioned relative to).
- 给元素设置了宽高以后,浏览器会阻止元素填满所有的空间,根据 margin: auto; 的要求,重新计算,并包裹一层新的盒子。developer.mozilla.org。the margin of the [absolutely positioned] element is then positioned inside these offsets.
- 既然块元素是绝对定位的,又脱离了普通文档流,因此浏览器在包裹盒子之前会给 margin-top 和 margin-bottom 设置一个相等的值。w3.org if none of the three [top, bottom, height] are‘auto’: if both‘margin-top’and‘margin-bottom’are‘auto’, solve the equation under the extra constraint that the two margins get equal values.?aka: center the block vertically
使用“完全居中”,有意遵照了标准 margin: auto; 样式渲染的规定,所以应当在与标准兼容的各种浏览器中起作用。
对齐
容器内对齐
使用“完全居中”,就可以在一个设置了 position: relative 的容器中做到完全居中元素了!
.center-container {
position: relative;
}
.absolute-center {
width: 50%;
height: 50%;
overflow: auto;
margin: auto;
position: absolute;
top: 0; left: 0; bottom: 0; right: 0;
}
接下来的示例会假设已经包含了以下样式,并且以逐步添加样式的方式提供不同的特性。
在可视区域内居中
想要使内容区在可视区域内居中么?设置 position: fixed 样式,并设置一个较高的 z -index 值,就可以做到。
.absolute-center.is-fixed {
position: fixed;
z-index: 999;
}
移动版 safari的说明:如果外面没有一层设置 position: relative 的容器,内容区会以整个文档的高度的中心点为基准居中,而不是以可视区域的高度中心点为基准居中。
偏移值
如果需要添加固定的标题,或者其他带偏移样式的元素,可以直接把类似 top: 70px; 的样式写进内容区域的样式中。一旦声明了 margin: auto; 的样式,内容块的 top
left
bottom
right
的属性值也会同时计算进去。
如果想让内容块在贴近侧边的过程中保持水平居中,可以使用 right: 0; left: auto; 让内容贴在右侧,或者使用 left: 0; right: auto; 使内容贴在左侧。
.absolute-center.is-fixed {
position: fixed;
z-index: 999;
}
带响应式
使用 absolute 的最大好处就是可以完美地使用带百分比的宽高样式!就算是 min-width/max-width 或者 min-height/max-height 也能够有如预期般的表现。
再进一步加上 padding 样式的话,absolute 式的完全居中也丝毫不会破坏!
.absolute-center.is-responsive {
width: 60%;
height: 60%;
min-width: 200px;
max-width: 400px;
padding: 40px;
}
带溢出内容
内容区高度大于可视区域或者一个 position: relative 的容器,其内容可能会溢出容器,或被容器截断。只要内容区域没有超出容器(没有给内容容器预留 padding 的话,可以设置 max-height: 100%; 的样式),那么容器内就会产生滚动条。
.absolute-center.is-overflow {
overflow: auto;
}
大小可调整
使用其他样式,或者使用 javascript 调整内容区的大小,也是不用手动重新计算的!如果设置了 resize 的样式,甚至可以让用户自行调节内容区域的大小。“完全居中”法,无论内容区怎么改变大小,都会保持居中。
设置了 min-/max- 开头的属性可以限制区块的大小而不用担心撑开容器。
.absolute-center.is-resizable {
min-width: 20%;
max-width: 80%;
min-height: 20%;
max-height: 80%;
resize: both;
overflow: auto;
}
如果不设置 resize: both 的样式,可以设置 transition 样式平滑地在大小间切换。一定要记得设置 overflow: auto 样式,因为改变大小后的容器高宽很有可能会小于内容的高宽。“完全居中”法是唯一一种能支持使用 resize: both 样式的方法。
使用注意:
- 需要设置 max-width/max-height 给内容区域留足够的空间,不然就有可能使容器溢出。
- resize 属性不支持移动版浏览器和 ie8-10,如果用户体验很重要的话,请确保用户可以有其他替代方法来改变大小。
- 同时使用 resize 样式和 transition 会使用户在开始改变大小时产生等于 transition 效果时间等长的延时。
图像
图像也同样有效!提供相应的 class,并指定样式 height: auto;,就得到了一张随着容器改变大小的响应式图片。
请注意,height: auto; 样式虽然对图片有效,如果没有用到了后面介绍的‘可变高技巧’,则会导致普通内容区域伸长以适应容器长度。
浏览器很有可能是根据渲染结果填充了图像高度值,所以在测试过的浏览器中,margin: auto; 样式就像是声明了固定的高度值一般正常工作。
html:
css:
.absolute-center.is-image {
height: auto;
}
.absolute-center.is-image img {
width: 100%;
height: auto;
}
可变高度
“完全居中”法的确需要声明容器高度,但是高度受 max-height 样式的影响,也可以是百分比。这非常适合响应式的方案,只需要设置好带溢出内容就行。
另一种替代方案是设置 display: table 样式居中,,不管内容的长度。这种方法会在一些浏览器中产生问题(主要是 ie 和 firefox)。我在 ell creative 的朋友 kalley 写了一个基于 modernizr 的测试,可以用来检查浏览器是否支持这种居中方案。现在这种方法可以做到渐进增强。
注意要点:这种方法会破坏浏览器兼容性,如果 modernizr 测试不能满足你的需求,你可能需要考虑其他的实现方案。
- 与大小可调整技术是不兼容的
- firefox/ie8中使用 display: table,内容区在垂直方向靠上,水平方向仍然居中。
- ie9/10中使用 display: table,内容区会跑到左上角。
- 移动版 safari 中内容区是水平对齐的,但是如果使用了百分比的宽度,水平方向上会稍稍偏离中心。
javascript:
/* modernizr test for variable height content */
modernizr.teststyles(‘#modernizr { display: table; height: 50px; width: 50px; margin: auto; position: absolute; top: 0; left: 0; bottom: 0; right: 0;}’, function(elem, rule) {
modernizr.addtest(‘absolutecentercontent’, math.round(window.innerheight / 2 – 25) === elem.offsettop);
});
css:
.absolutecentercontent .absolute-center.is-variable {
display: table;
height: auto;
}
其他方法
“完全居中”法是解决居中问题的好方法,同时也有许多可以满足不同需求的其他方法。最常见的,推荐的方法有负 margin 值、transform 法、table-cell 法、inline-block 法、以及现在出现的 flexbox 法,这些方法其他文章都有深入介绍,所以这里只会稍稍提及。
负 margin 值
这或许是最常用的方法。如果知道了各个元素的大小,设置等于宽高一半大小的负 margin 值(如果没有使用 box-sizing: border-box 样式,还需要加上 padding 值),再配合 top: 50%; left: 50%; 样式就会使块元素居中。
需要注意的是,这是按照预想情况也能在工作在 ie6- 7 下的唯一方法。
.is-negative {
width: 300px;
height: 200px;
padding: 20px;
position: absolute;
top: 50%; left: 50%;
margin-left: -170px; /* (width padding)/2 */
margin-top: -120px; /* (height padding)/2 */
}
好处:
- 浏览器兼容性非常好,甚至支持 ie6-7
- 需要的编码量很少
同时注意:
- 这是个非响应式的方法,不能使用百分比的大小,也不能设置 min-/max- 的最大值最小值。
- 内容可能会超出容器
- 需要为 padding 预留空间,或者需要使用 box-sizing: border-box 样式。
transform 法
和“完全居中”法的好处一样,简单有效,同时支持可变高度。为内容指定带有厂商前缀的 transform: translate(-50%,-50%)和 top: 50%; left: 50%; 样式就可以让内容块居中。
.is-transformed {
width: 50%;
margin: auto;
position: absolute;
top: 50%; left: 50%;
-webkit-transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);
}
好处:
- 内容高度可变
- 代码量小
同时注意:
- 不支持 ie8
- 需要写厂商前缀
- 会和其他 transform 样式有冲突
- 某些情况下的边缘和字体渲染会有问题
table-cell 法
这种可能是最好的方法,因为高度可以随内容改变,浏览器支持也不差。主要缺陷是会产生额外的标签,每一个需要居中的元素需要三个额外的 html 标签。
html:
css:
.center-container.is-table {display: table;}
.is-table .table-cell {
display: table-cell;
vertical-align: middle;
}
.is-table .center-block {
width: 50%;
margin: 0 auto;
}
好处:
- 内容高度可变
- 内容溢出则能自动撑开父元素高度
- 浏览器兼容性好
同时注意:
- 需要额外的 html 标签
inline-block 法
迫切需要的方法:inline-block 法居中。基本方法是使用 display: inline-block
, vertical-align: middle
样式和伪元素让内容块在容器中居中。我的实现用到了几个在其他地方见不到的新技巧解决了一些问题。
内容区声明的宽度不能大于容器的 100% 减去 0.25em 的宽度。就像一段带有长文本的区域。不然,内容区域会被推到顶端,这就是使用:after 伪类的原因。使用:before 伪类则会让元素有 100% 的大小!
如果内容块需要尽可能大地占用水平空间,可以为大容器加上 max-width: 99%; 样式,或者考虑浏览器和容器宽度的情况下使用 max-width: calc(100% – 0.25em) 样式。
这种方法和 table-cell 的大多数好处相同,不过最初我放弃了这个方法,因为它更像是 hack。不管这一点的话,浏览器支持很不错,而且也被证实是很流行的方法。
html:
css:
.center-container.is-inline {
text-align: center;
overflow: auto;
}
.center-container.is-inline:after,
.is-inline .center-block {
display: inline-block;
vertical-align: middle;
}
.center-container.is-inline:after {
content: ”;
height: 100%;
margin-left: -0.25em; /* to offset spacing. may vary by font */
}
.is-inline .center-block {
max-width: 99%; /* prevents issues with long content causes the content block to be pushed to the top */
/* max-width: calc(100% – 0.25em) /* only for ie9 */
好处:
- 内容高度可变
- 内容溢出则能自动撑开父元素高度
- 浏览器兼容性好,甚至可以调整支持 ie7
同时注意:
- 需要额外容器
- 依赖于 margin-left: -0.25em 的样式,做到水平居中,需要为不同的字体大小作调整
- 内容区声明的宽度不能大于容器的 100% 减去 0.25em 的宽度
flexbox 法
css 未来发展的方向就是采用 flexbox 这种设计,解决像垂直居中这种共同的问题。请注意,flexbox 有不止一种办法居中,他也可以用来分栏,并解决奇奇怪怪的布局问题。
.center-container.is-flexbox {
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-align: center;
-moz-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-box-pack: center;
-moz-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
}
好处:
- 内容可以是任意高宽,溢出也能表现良好
- 可以用于各种高级布局技巧
同时注意:不支持 ie8-9
- 需要在 body 上写样式,或者需要额外容器
- 需要各种厂商前缀兼容现代浏览器
- 可能有潜在的性能问题
最后的建议
各项技术都有各自的好处,采取什么样的方法,取决于你所支持的浏览器,以及现有标签的结构。请使用上面提供对照表帮你选出最符合你需要的方法。
“完全居中”法简单方便,迅速及时。以前使用负 margin 值的地方,都可以使用 absolute 居中。无需繁琐的数学计算,无需额外标签,而且可以随时改变大小。
如果网站需要可变高度的内容,而且同时照顾到浏览器兼容性的话,可以尝试 table-cell 和 inline-block 技术,如果想尝试新鲜事物的话,可以使用 flexbox,并享受这种高级技术带来的好处。