使用margin:auto垂直对齐一个div

159

我知道如果使用margin:0 auto;,我们可以水平居中一个div。那么margin:auto auto;应该能像我想的那样工作吗?也能垂直居中吗?

为什么vertical-align:middle;也不起作用呢?

.black {
    position:absolute;
    top:0;
    bottom:0;
    left:0;
    right:0;
    background:rgba(0,0,0,.5);
}
.message {
    background:yellow;
    width:200px;
    margin:auto auto;
    padding:10px;
}
<div class="black">
    <div class="message">
        This is a popup message.
    </div>
</div>

JSFiddle


2
强烈建议阅读并实施@zpr在下面关于Flexbox的答案。它在今天得到了很好的支持,您的CSS将会更加干净。 - Govind Rai
如果((new Date()).getFullYear() > 2017) useFlexBox = true; - brandito
15个回答

203

2020年8月更新:

尽管下面的内容仍然值得阅读, 但我们现在已经有Flexbox了,所以按照这个答案使用它即可。


以下方法无法使用:

vertical-align:middle 因为它不适用于块级元素

margin-top:automargin-bottom:auto 因为它们的计算值会被计算为

margin-top:-50% 因为基于百分比的margin值是相对于包含块的宽度计算的

事实上,文档流的性质和元素高度计算算法使得在父元素内部垂直居中一个元素使用margin是不可能的。每当垂直margin值被更改时,它会触发父元素高度重新计算(重新布局),这将进一步触发原始元素的重新居中...使其成为一个无限循环。

你可以使用:

像这样的一些解决方案适用于您的情况; 这三个元素必须像这样嵌套:

.container {
    display: table;
    height: 100%;
    position: absolute;
    overflow: hidden;
    width: 100%;
}
.helper {
    #position: absolute;
    #top: 50%;
    display: table-cell;
    vertical-align: middle;
}
.content {
    #position: relative;
    #top: -50%;
    margin: 0 auto;
    width: 200px;
    border: 1px solid orange;
}
<div class="container">
    <div class="helper">
        <div class="content">
            <p>stuff</p>
        </div>
    </div>
</div

JSFiddle 在 Browsershot 中正常运行。


11
# 是一种 hack,它可以让规则只被 IE7 及以下版本解释。你可以选择将这些规则包含在专门针对 IE 的样式表中,例如使用条件注释等方法。 - Oleg
3
感谢肯定这种情况的原因,基于宽度计算的利润百分比公式让我大开眼界。+1 - ricosrealm
2
我对“无限循环”语句有所怀疑。 - Barun
157
人类几年前已经登上了月球,但我们仍需应对这些烦人的事情。在浏览器中垂直对齐元素,天啊。 - user151496
4
在IE9及以上版本中,position: absolute; top: 50%; transform: translateY(-50%);这种写法也很常用且可行(不像top:50%; margin: -$halfHeight需要事先知道高度)... - Frank N
显示剩余7条评论

166
自2012年问这个问题以来,我们在浏览器支持flexbox方面取得了长足的进步,我觉得这个答案是必要的。如果父容器的显示为flex,则是的,margin: auto auto(也称为margin: auto)将水平和垂直居中它,无论它是内联元素还是块级元素。请保留HTML标签。

#parent {
    width: 50vw;
    height: 50vh;
    background-color: gray;
    display: flex;
}
#child {
    margin: auto auto;
}
<div id="parent">
    <div id="child">hello world</div>
</div>

请注意,宽度/高度不必绝对指定,比如在此示例中使用相对于视口的大小example jfiddle
尽管发布时浏览器对弹性盒子的支持达到了历史最高水平,但仍有许多浏览器不支持或需要供应商前缀。请参阅http://caniuse.com/flexbox以获取更新的浏览器支持信息。
更新
由于这个答案引起了一些关注,我还想指出,如果您正在使用display:flex并希望将容器中的所有元素居中,那么根本不需要指定margin。

#parent {
    width: 50vw;
    height: 50vh;
    background-color: gray;
    display: flex;
    align-items: center; /* vertical */
    justify-content: center; /* horizontal */
}
<div id="parent">
    <div>hello world</div>
</div>


7
父元素 { display: flex; } 子元素 { margin: auto 0; } 真的很棒。 - Arek Kostrzeba
哇,伙计,你真是个超级巨星啊!我真的只能给你点赞一次了!!! - PirateApp
当您可能也对fit-content问题感到困惑时,这是一个很好的答案。通过在容器上设置flex,内容div不需要设置任何属性。 - Eric
1
这绝对是2018年最好、最优雅的解决方案,谢谢。 - SilverSurfer
我想补充一下,子元素仍然需要“margin: auto”,否则如果它的高度超过屏幕,它将被剪切在顶部。 - Owyn
显示剩余2条评论

68

这是我找到的最佳解决方案:http://jsfiddle.net/yWnZ2/446/ 可在Chrome、Firefox、Safari、IE8-11和Edge中使用。

如果您已经声明了height(例如height: 1emheight: 50%等),或者这是一个浏览器知道其高度的元素(如imgsvgcanvas),那么您只需要这个代码就可以垂直居中:

.message {
    position: absolute;
    top: 0; bottom: 0; left: 0; right: 0;
    margin: auto;
}

通常情况下,您需要指定一个widthmax-width,以便内容不会拉伸到整个屏幕/容器的长度。

如果您将其用于模态框,并希望始终将其置于视口中心并与其他内容重叠,请对两个元素都使用position: fixed;而非position: absolutehttp://jsfiddle.net/yWnZ2/445/

这里有一篇更完整的说明:http://codepen.io/shshaw/pen/gEiDt


3
这并不一定将它置于其父元素的中心位置。如果你只是想要将它放置在页面中央,这是一个很好的技巧。 - Joel Mellon
3
只需在父元素中添加 position: relative,该元素就会居中于其内部。如果您想了解更多信息,可以阅读我在Smashing Magazine上关于该技术的详细介绍:http://coding.smashingmagazine.com/2013/08/09/absolute-horizontal-vertical-centering-css/。 - shshaw
有时候,绝对定位是基于父元素或者祖先元素(相对于body),而相对定位则可能是基于更高层级的祖先元素(相对于父元素)。也许那些知道为什么会发生这种情况的人可以更好地掌握这种技巧 - 我从来没有真正研究过这些问题,但我知道从绝对定位切换到相对定位本身并不是解决这个问题的方法。我读了一点你的文章,看起来绝对定位和相对定位都是基于第一个绝对或相对定位的祖先元素,这是正确的吗? - Joel Mellon
我有点慢。我刚刚重新阅读了你上面的评论。我没有注意到你说要将它添加到“parent”中 - 明白了。非常感谢! - Joel Mellon
1
@commonpike IE8/9唯一的问题是如果您使用display: table来处理可变高度内容。否则,此方法应按预期工作。请阅读writeup以获取更多细节。您还可以在IE8/9中测试full view,以查看是否存在任何问题。 - shshaw
显示剩余7条评论

26

编辑:现在已经是2020年了,我会使用flexbox代替。

原始回答:

Html

<body>
  <div class="centered">
  </div>
</body>

CSS

.centered {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

不适用于IE 8及更早版本的IE。由于transform属性仅在9.0及以上版本中受支持(带有前缀-ms-),因此无法在IE 8及更早版本中正常工作。(即10不再需要前缀)。 - DevWL
8
没错,我不在乎IE8。 - Gal Margalit
作者在他的问题中标记了HTML5 ☺ - Gal Margalit

10

我知道这个问题是来自2012年的,但是我发现了最简单的方法,并想分享出来。

HTML:

<div id="parent">
     <div id="child">Content here</div>
</div>

和 CSS:

#parent{
     height: 100%;
     display: table;
}    
#child {
     display: table-cell;
     vertical-align: middle; 
}

8
如果您知道要居中的 div 的高度,可以将其绝对定位于其父元素内,然后将 top 值设置为 50%。这将使子 div 的顶部位于其父元素的一半处,即太低了。通过将其 margin-top 设置为其高度的一半来拉回它。现在,您已经将子 div 的垂直中点放置在父元素的垂直中点上 - 实现了垂直居中!
示例:

.black {
    position:absolute;
    top:0;
    bottom:0;
    left:0;
    right:0;
    background:rgba(0,0,0,.5);
}
.message {
    background:yellow;
    width:200px;
    margin:auto auto;
    padding:10px;
    position: absolute;
    top: 50%;
    margin-top: -25px;
    height: 50px;
}
<div class="black">
    <div class="message">
        This is a popup message.
    </div>
</div>

http://jsfiddle.net/yWnZ2/2/


1
margin-top 不能以相对于元素高度的百分比设置,因此您最终会得到一个依赖尺寸的修复。 - Oleg
1
这正是我在答案中所说的吗?“如果您知道要居中的 div 的高度”。而我并没有说 OP 应该在 margin-top 中使用 %。 - tuff
我不同意这个解决方案,因为它将你锁定在预定义的元素高度上 - 但是你的评论很有道理。你可能想在答案中反映这一点。 - Oleg
3
好的,我已经加粗了你忽略的部分,希望现在更清楚了。 - tuff
1
@o.v.:如果元素没有固定的高度,您可以使用JS获取计算出的高度,然后相应地设置负上边距。在我看来,这仍然是垂直居中的最佳方法。 - daGUY
+1 - 我们已经有一个用作img边界框的div,它具有固定的高度。 - Izkata

4
这两个解决方案只需要两个嵌套的元素。
第一个 - 相对和绝对定位,如果内容是静态的(手动居中)。
.black {
    position:relative;
    min-height:500px;
    background:rgba(0,0,0,.5);

}
.message {
    position:absolute;
    margin: 0 auto;
    width: 180px;
    top: 45%; bottom:45%;  left: 0%; right: 0%;
}

https://jsfiddle.net/GlupiJas/5mv3j171/

或者针对流体设计 - 如果需要精确的内容居中,请使用下面的示例:

.message {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

https://jsfiddle.net/GlupiJas/w3jnjuv0/

如果内容超过窗口高度的50%,则需要设置'min-height'。您还可以使用媒体查询来操作移动设备和平板电脑的高度,但前提是您要进行响应式设计。

我想您可以进一步使用简单的JavaScript / JQuery脚本来操纵min-height或fixed height(如果有必要)。

其次 - 如果内容是流体的,您还可以使用表格和表格单元格CSS属性进行垂直对齐和文本居中:

/*in a wrapper*/  
display:table;   

并且。
/*in the element inside the wrapper*/
display:table-cell;
vertical-align: middle;
text-align: center;

它的工作和规模完美无缺,通常用作响应式网页设计解决方案,使用网格布局和媒体查询来操作对象的宽度。

.black {
    display:table;
    height:500px;
    width:100%;
    background:rgba(0,0,0,.5);

}
.message {
    display:table-cell;
    vertical-align: middle;
    text-align: center;
}

我更喜欢使用表格来实现内容居中,但在某些情况下,相对绝对定位会更好,特别是当我们不想保持内容对齐的精确比例时。

https://jsfiddle.net/GlupiJas/4daf2v36/


3

.black {
    display:flex;
    flex-direction: column;
    height: 200px;
    background:grey
}
.message {
    background:yellow;
    width:200px;
    padding:10px;
    margin: auto auto;
}
<div class="black">
    <div class="message">
        This is a popup message.
    </div>
</div>


请问您能否与我们分享一下这个解决方案是关于什么的?另外,我发现您的“弹出消息”在底部没有居中。 - Alex
我之前漏掉了一些东西,但现在已经修正了,可以保持div垂直居中。你现在可以检查一下。 - Seetpal singh

2

.black {
    position:absolute;
    /*
        Replace with a one line inset property.
    top:0;
    bottom:0;
    left:0;
    right:0;
    */
    inset: 0;
    background:rgba(0,0,0,.5);
    /*
        Since no one has mentioned it yet,
        here it is the grid display and
        the place-content property.
    */
    display:grid;
    place-content: center;
}
.message {
    background:yellow;
    width:200px;
    /*
        There's no point here.
    margin:auto auto;
    */
    padding:10px;
}
<div class="black">
    <div class="message">
        This is a popup message.
    </div>
</div>


1
变量高度,上下边距自动。

.black {background:rgba(0,0,0,.5);
width: 300px;
height: 100px;
display: -webkit-flex; /* Safari */
display: flex;}
.message{
background:tomato;
margin:auto;
padding:5%;
width:auto;
}
<div class="black">
<div class="message">
    This is a popup message.
</div>

变量高度,上下边距自动。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接