小tip: margin:auto实现绝对定位元素的水平垂直居中

一、悠悠哉哉说点什么

本来我有个很好的计划,就是本文用漫画来写,把话痨的火影漫画的文字重新抹掉,然后填本文相关的技术文字

哈,是不是很好啊!但是,想到了一个残酷的现实——流量,我一个月只有30G流量,几乎月月爆棚,要是这里全部用火影的图片要实现,页面没个1M搞不下来哈~,文章要是3000访问,就差不多3G,天哪,我表示压力很大。于是,我决定还是中规中矩用文字加一两小截图表示下吧~

鸣人君对博主的维护口盾 张鑫旭-鑫空间-鑫生活

二、绝对定位元素的居中实现

如果要问如何CSS实现绝对定位元素的居中效果,很多人心里已经有答案了。

兼容性不错的主流用法是:

.element {
    width: 600px; height: 400px;
    position: absolute; left: 50%; top: 50%;
    margin-top: -200px;    /* 高度的一半 */
    margin-left: -300px;    /* 宽度的一半 */
}

但,这种方法有一个很明显的不足,就是需要提前知道元素的尺寸。否则margin负值的调整无法精确。此时,往往要借助JS获得。

CSS3的兴起,使得有了更好的解决方法,就是使用transform代替margin. transformtranslate偏移的百分比值是相对于自身大小的,于是,我们可以:

.element {
    width: 600px; height: 400px;
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%);    /* 50%为自身尺寸的一半 */
}

于是乎,无论绝对定位元素的尺寸是多少,其都是水平垂直居中显示的。

然,问题很明显,兼容性不好。IE10+以及其他现代浏览器才支持, IE9(-ms-), IE10+以及其他现代浏览器才支持。中国盛行的IE8浏览器被忽略是有些不适宜的(手机web开发可忽略)。

实际上,绝对定位元素的居中实现还有另外一种方法,可以说是权衡了上面的尺寸自适应以及兼容性的一个方案,其实现的核心是margin:auto.

三、margin:auto实现绝对定位元素的居中

首先,我们来看下CSS代码:

.element {
    width: 600px; height: 400px;
    position: absolute; left: 0; top: 0; right: 0; bottom: 0;
    margin: auto;    /* 有了这个就自动居中了 */
}

代码两个关键点:

  1. 上下左右均0位置定位;
  2. margin: auto

于是,就居中了。上面代码的width: 600px height: 400px仅是示意,你修改为其他尺寸,或者不设置尺寸(需要是图片这种自身包含尺寸的元素),都是居中显示的。很有意思的~~

您可以狠狠地点击这里:margin:auto与绝对定位元素的垂直居中demo

点击demo中间的按钮

点击demo页面中间的按钮,让原本static的框框absolute化,可以发现其是水平垂直居中的。

不知诸位新技能get否?

对了,该方法IE8+以及其他浏览器都是OK的。

8-10月份浏览器的使用比例

上图为8~10月份,百度流量统计员给出的浏览器访问数据。IE6+IE7大概14%的样子。显然,很快,此方法就要开始称霸PC武林了!

三、悠悠哉哉再说点什么

可能有人会问,为何margin: auto;会让绝对定位元素居中了呢?哈哈,原因是………………
.
.
.
.
我也不知道!

可能需要查询规范寻找一些线索。但,待会儿我还有篮球比赛,恕我没有足够精力去深入。欢迎有相关研究的达人分享其内部机制原理,不甚感谢!

更新于2017年2月18日
今天正好有看到自己的这篇文章,我更新下原因吧!

当一个绝对定位元素,其对立定位方向属性同时有具体定位数值的时候,流体特性就发生了,例如:

<div class="box"></div>
.box {
  position: absolute;
  left: 0; right: 0;
}

如果只有left属性或者只有right属性,则由于包裹性此时.box宽度是0。但是,在本例中,因为left/right同时存在,因此宽度就不是0,而是自适应于.box包含块的padding box宽度,也就是随着包含块padding box的宽度变化,.box的宽度也会跟着一起变。

具有流体特性绝对定位元素的margin:auto的填充规则和普通流体元素一模一样:

  1. 如果一侧定值,一侧autoauto为剩余空间大小;
  2. 如果两侧均是auto, 则平分剩余空间;

例如,下面的CSS代码:

.father {
    width: 300px; height:150px;
    position: relative;
}
.son { 
    position: absolute; 
    top: 0; right: 0; bottom: 0; left: 0;
}

此时.son这个元素的尺寸表现为“格式化宽度和格式化高度”,和<div>的“正常流宽度”一样,同属于外部尺寸,也就是尺寸自动填充父级元素的可用尺寸的,然后,此时我们给.son设置尺寸,例如:

.son { 
    position: absolute; 
    top: 0; right: 0; bottom: 0; left: 0;
    width: 200px; height: 100px;
}

此时宽高被限制,原本应该填充的空间就被多余了出来,这多余的空间就是margin:auto计算的空间,因此,如果这时候,我们再设置一个margin:auto,那么:

.son { 
    position: absolute; 
    top: 0; right: 0; bottom: 0; left: 0;
    width: 200px; height: 100px;
    margin: auto;
}

我们这个.son元素就水平和垂直方向同时居中了。因为,auto正好把上下左右剩余空间全部等分了,自然就居中啦!

// zxx: 更新end—-

欢迎讨论,欢迎交流。

(本篇完)

分享到:

标签: , , , , ,

赞助商推荐(我也要赞助)

想学到点真东西? ×
如果你有1~3年前端开发经验,不妨 ×
想要工资30K? ×


发表评论(目前47 条评论)

  1. renmu说道:

    想知道为什么在普通流中 margin:auto;不能垂直居中,而在absolute中可以

  2. tom说道:

    今天面试了一个前端关于垂直居中的问题,他跟我说absolute后margin:auto就可以了,我说他是胡扯,今天在这里道歉

  3. somethingGone说道:

    鑫哥! 定位元素的margin值的left和top相对于谁来定位?
    层叠上下文那里,如果子元素也创建了层叠上下文,那么在渲染的时候要如何处理这个子元素?
    那如果这个子元素有z-index=-1呢,他会到谁下面去? 多层嵌套层叠上下文会怎么处理? 这个问题困扰了我好久哇~~ 求指点

  4. Coande说道:

    这种方法也还是不能直接使未知宽度、高度的div居中吧?

  5. 今天只做一件事说道:

    今天看了好多你的文章,明白了很多,相见恨晚,简直像看小说哈哈哈

  6. 长缨在手说道:

    为何设置margin-top时 直接跨越了上面最接近的函数

  7. 大象说道:

    还有一种办法是父级display:table;子级display:table-cell; vertical-align:center;

  8. IE8说道:

    IE8里面无效

  9. qing说道:

    ie7不兼容啊,不兼容啊。

  10. 皮蛋周说道:

    鑫哥,上面这个“三、margin:auto实现绝对定位元素的居中”,在按钮按下之前,element就是居中的,按下以后多了个.dialog_absolute { position: absolute; left: 0; top: 0; right: 0; bottom: 0; z-index: 1; }。结果还是居中,那么我想问加类名dialog_absolute有什么作用?这里可能转牛角尖了,望看到的人教导教导

    • 菜鸟-没想法的杰说道:

      就是让他水平垂直都居中啊
      用了position 之后我们的margin:0 auto 失效。
      然而我们要水平垂直都居中。那么就用.dialog_absolute的方法。

  11. 云库网说道:

    这里有一篇关于居中的文章《CSS3 Flexbox轻松实现元素的水平居中和垂直居中》可以作为这里的补充说明!http://yunkus.com/article/css3/286.html

  12. 刘东奇说道:

    博主总结的经验总是能解决我的难题,真是佩服

  13. samlin说道:

    原因大概是~~float为什么可以让文字环绕,人家愿意呗。

  14. wteamxq说道:

    “IE10+以及其他现代浏览器才支持”
    transform 2d Transforms 不是IE9(-m-transform)就支持了么?为什么说IE10才支持?

  15. 大地说道:

    方法很好,让我大开眼界,不过就是有点hack的味道

  16. sleelily说道:

    还是不明白为什么,margin:0 auto; 不需要设置top,left等值,而这个就需要,果然是黑科技么?

  17. QQ80805588说道:

    人精这你也知道

  18. = =说道:

    啊啊啊啊啊啊大感谢!!!!非常感谢!!!!

  19. taodongsheng说道:

    鑫哥,我在你这里学到了不少css新的思想,感谢你,我想知道为什么这篇文章讲的内容,无法在ie7下实现居中呢

  20. sss说道:

    必须要定义高度,不然按照w3c的说法

    If all three of ‘top’, ‘height’, and ‘bottom’ are auto, set ‘top’ to the static position and apply rule number three below.

  21. blwoosky说道:

    Android 2.+默认浏览器不兼容

  22. 前端渣渣说道:

    第一次来鑫哥哥的博客就不想走了~~鑫哥哥,有问题可以在这里提么?

  23. Tommy说道:

    鑫哥好,默默关注你很久了,哈哈哈,学到不少东西,在此表示一下感谢,喜欢你搞笑的风格!么么哒

  24. luckystar2010说道:

    margin:auto,IE8不行

  25. 于江水说道:

    貌似文中的 absolute 都写成了 position: aboslute; 。。。。。。。。。。

  26. MicroMao说道:

    国内网站最早是在百度云上看到相关用法的。侧边是这么写的.aside{position:absolute;left:0;top:0;bottom:0;width:210px;},用来适应父元素高度100%,对于脱离文档流的布局方式,子元素是不知道父元素的高度的,但是很多时候有脱离文档流布局(定位和浮动)和子元素适配父元素高度的双重需求,就可以用这种方法,兼容IE7+,没测IE6。至于垂直水平居中是基于此的更高应用。国外网站最早在http://codepen.io/shshaw/full/gEiDt上看到这种写法,并给这种技术取名做absolute centering。感兴趣的可以看下。

  27. singlexyz说道:

    看起来像是 left/right为0时,让margin:0 auto生效
    top/bottom为0则是让margin:auto 0;生效
    至于为什么会生效,估计是这样:

    刚刚试着把left/right设为同等值但不为0,如100,效果不变
    假设页面宽是1000,盒子宽300,left = right = 100;
    那剩下可活动的500,则会让margin:auto “平分”掉
    left=right=0时,用调试工具看,它的margin左右都到了边缘
    而left=right=100时,margin部份则是各距离边缘100
    这时就很好理解了,而垂直居中则是同理。
    至于ie6/7无效,估计是定位下margin的auto值没起作用

    顺便一提,没定位的情况下,margin:auto不会垂直居中的,这有点恶心
    但照上面“定位平分”的方法却能做到,顺便请教下张大人,left=right=100
    right实际是生效了,但视觉上为什么还是left=100不会被后面的覆盖

  28. 702017364说道:

    刚刚测试的时候发现博主将决定定位的值写错了

  29. 702017364说道:

    垂直居中的东西,茶艺花园里面很早就有这个了,ie8+用display:table,而ie7-用outer绝对定位top:50%,inner用相对定位top:-50%

    一直在关注博主的东东,学到很多东西,最近想到一个左中右排版的东西(不清楚有没有别人想到过,很想跟博主分享一下),利用display:inner-block改变子元素(即要实现左中右排版的东西),外部让子元素不换行,然后定义左右内边距(左右内边距定于左右子元素的宽),第一个子元素用外边距挪移到外部元素的左内边距里面,为了兼容ie7-,要在外部元素中关闭滚动条–(这样实现左中右排版可以避免定位,而且中间的宽度可以自由化)

  30. 比如我这样:
    结构是:

    div>p.center-middle>一段垂直居中的文字

    外层div设置为position:relative;
    .center-middle{
    position:absolute;
    top:0;
    bottom:0;
    left:0;
    right:0;
    margin:auto;
    }
    上面的p是不垂直居中的。
    如果换成一个图片便可以。
    这样为什么?

  31. 逍遥哥说道:

    不错,还不能大规模使用,都是IE的错

  32. Ricky说道:

    用过linode的人表示,用linode主机吧,别再用万网的了。真心的。2T流量哦。
    Linode
    1 GB RAM
    8 CPU (1x priority)
    48 GB Storage
    2 TB Transfer
    $20 / month

  33. Herrington Darkholme说道:

    定高 div 被设置为 top:0; bottom:0;。但是因为它有固定高度,其实并不能和上下都间距为 0,因此 margin:auto; 会使它居中。
    http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-height

    具体而言,就是这个式子:
    ‘top’ + ‘margin-top’ + ‘border-top-width’ + ‘padding-top’ + ‘height’ + ‘padding-bottom’ + ‘border-bottom-width’ + ‘margin-bottom’ + ‘bottom’ = height of containing block

    当width, height全部被指定,而margin为auto时,可计算出实际margin值。
    其实当width,height未指定时,会有限计算width和height

  34. ddcat说道:

    拿高度来说吧(宽度是一样的),css的视觉格式化模型是这样的:
    ‘top’ + ‘margin-top’ + ‘border-top-width’ + ‘padding-top’ + ‘height’ + ‘padding-bottom’ + ‘border-bottom-width’ + ‘margin-bottom’ + ‘bottom’ = 包含块的高度

    当top/height/bottom 这3个值不是auto,而 margin:auto ,则:
    margin-top=margin-bottom=(包含块的高度 – 定位元素高度)/2

    http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-height

    这个原理其实和普通block元素使用margin:0 auto可以水平居中是类似的。