为什么“margin:auto”不是垂直居中的元素?

时间:2022-11-10 15:06:13

As you can see in the demo below, margin: auto; centers the blue div horizontally, but not vertically. Why not?

正如您在下面的演示中所看到的,margin:auto;将蓝色div水平居中,但不垂直居中。为什么不?

.box {
  border: 1px solid red;
  width: 100px;
  height: 100px;
}
.center {
  background: blue;
  width: 50px;
  height: 50px;
  margin: auto;
}
<div class="box">
  <div class="center"></div>
</div>

My question is not asking for workarounds.

我的问题不是要求解决方法。

5 个解决方案

#1


33  

As mentioned, this behavior is specified in section 10.6.2 of CSS2.1, and has remained unchanged from CSS2.

如上所述,此行为在CSS2.1的第10.6.2节中指定,并且与CSS2保持不变。

Block boxes are stacked vertically from top to bottom in normal flow. Furthermore, vertical margins may collapse, and only do so under certain circumstances (in your demo, the border on the parent element will prevent any margins on the child element from collapsing with its own). If you only have one such block box, and the height of the containing block is auto, then its top and bottom margins will be zero anyway. But if you have more than one block box in the same flow, or even out-of-flow boxes affecting the layout of in-flow boxes (in the case of clearance for example), how would you expect auto margins to resolve for those in-flow boxes?

在正常流动中,块箱从顶部到底部垂直堆叠。此外,垂直边距可能会崩溃,并且只在某些情况下才会崩溃(在演示中,父元素上的边框将阻止子元素上的任何边距与其自身折叠)。如果你只有一个这样的块盒,并且包含块的高度是自动的,那么无论如何它的顶部和底部边距都将为零。但是,如果在同一流程中有多个块框,或者甚至是影响流入框布局的流出框(例如,在清除的情况下),您会如何期望自动边距为这些框解决流入箱?

This is why auto left and right margins are likewise zeroed out for inline elements (including atomic inlines) and floats (though horizontal margins never collapse). Inline-level boxes are laid along line boxes, and floats too obey unique layout rules.

这就是为什么自动左右边距同样归零为内联元素(包括原子内联)和浮点数(尽管水平边距永不崩溃)。内联级框沿线框放置,浮动也遵循独特的布局规则。

Absolutely positioned boxes are a different story: since they are never aware of any other boxes in the same positioning context as themselves, auto top and bottom margins can be calculated for them with respect to their containing blocks without having to worry about any other boxes ever interfering.

绝对定位的盒子是一个不同的故事:因为他们从来没有意识到与自身相同的定位环境中的任何其他盒子,所以可以针对它们的包含块计算自动顶部和底部边距,而不必担心任何其他盒子干扰。

Flexbox is also a different story: what sets flex layout apart from block layout is that flex items are by definition always aware of other flex items in the same flex formatting context, including the fact that there are none. In particular, neither can floats intrude into the flex container, nor can you float flex items to subvert this (although you can still remove a child element from flex layout completely with absolute positioning). Margins behave very differently with flex items due in part to this. See sections 4.2, 9.5 and 9.6.

Flexbox也是一个不同的故事:将flex布局与块布局区分开来的是,Flex项目根据定义始终知道同一个flex格式化上下文中的其他flex项目,包括没有的事实。特别是,既不能浮动进入弹性容器,也不能浮动弹性项来破坏它(尽管你仍然可以通过绝对定位完全从弹性布局中移除子元素)。由于部分原因,边距与弹性项目的表现非常不同。见4.2,9.5和9.6节。

#2


29  

Why...because the W3C spec says so.

为什么......因为W3C规范是这样说的。

If 'margin-top', or 'margin-bottom' are 'auto', their used value is 0.

如果'margin-top'或'margin-bottom'为'auto',则其使用值为0。

As to the actual "why"...the query should really be addressed there.

至于实际的“为什么”...这个问题应该真正解决。

#3


16  

It doesn't center the element vertically because it is a block-level element in the normal flow. Thus, the following rule applies:

它不会垂直居中元素,因为它是正常流程中的块级元素。因此,以下规则适用:

If margin-top, or margin-bottom are auto, their used value is 0.

如果margin-top或margin-bottom为auto,则其使用值为0。

It's also worth pointing out that the rule above also applies to the following elements as well: (see points 10.6.2 and 10.6.3 for more information and conditions).

值得指出的是,上述规则也适用于以下要素:(有关更多信息和条件,请参见第10.6.2和10.6.3节)。

  • Inline replaced elements
  • 内联替换元素
  • Block-level replaced elements in normal flow
  • 正常流程中的块级替换元素
  • inline-block replaced elements in normal flow
  • 内联块在正常流程中替换了元素
  • Floating replaced elements
  • 浮动替换元素
  • Block-level non-replaced elements in normal flow when overflow computes to visible
  • 溢出计算为可见时,正常流程中的块级非替换元素

With that being said, absolutely positioned, non-replaced elements that don't have top, height, and bottom values of auto are an exception to this rule. The following applies from point 10.6.4:

话虽如此,绝对定位,没有顶部,高度和底部值auto的非替换元素是此规则的一个例外。以下适用于第10.6.4点:

If none of the three top, height, and bottom are auto and if both margin-top and margin-bottom are auto, solve the equation under the extra constraint that the two margins get equal values.

如果三个顶部,高度和底部都不是自动的,并且如果margin-top和margin-bottom都是auto,则在额外约束条件下求解等式,即两个边距得到相等的值。

See the example below demonstrating how an absolutely positioned element is vertically centered using margin: auto. It works because none of the three properties top, height, and bottom have a value of auto:

请参阅下面的示例,演示绝对定位元素如何使用margin:auto垂直居中。它的工作原理是因为top,height和bottom这三个属性都没有auto值:

.box {
  border: 1px solid red;
  width: 100px;
  height: 100px;
  position: relative;
}
.center {
  background: blue;
  width: 50px;
  height: 50px;
  margin: auto;
  position: absolute;
  top: 0; right: 0;
  bottom: 0; left: 0;
}
<div class="box">
  <div class="center"></div>
</div>

In addition, it's probably worth pointing out the following rule as well:

此外,它可能值得指出以下规则:

If one of margin-top or margin-bottom is auto, solve the equation for that value. If the values are over-constrained, ignore the value for bottom and solve for that value.

如果margin-top或margin-bottom中的一个是auto,则求解该值的等式。如果值过度约束,则忽略bottom的值并求解该值。

This means that if the absolutely positioned element has a margin-top value of auto and a margin-bottom value of 0 (i.e., margin: auto auto 0), the element would be absolutely positioned at the bottom relative to the parent like in the example below:

这意味着如果绝对定位元素的margin-top值为auto且margin-bottom值为0(即margin:auto auto 0),则该元素将绝对位于相对于父元素的底部,如示例如下:

.box {
  border: 1px solid red;
  width: 100px;
  height: 100px;
  position: relative;
}
.center {
  background: blue;
  width: 50px;
  height: 50px;
  margin: auto auto 0;
  position: absolute;
  top: 0; right: 0;
  bottom: 0; left: 0;
}
<div class="box">
  <div class="center"></div>
</div>

#4


13  

Why doesn't margin:auto work vertically?

为什么没有保证金:自动垂直工作?

Actually, it does – just not for every display value.

实际上,它确实 - 只是不是每个显示值。

If display is flex, margin: auto centers both vertically and horizontally.

如果显示为flex,则margin:auto垂直和水平居中。

The same applies to display: inline-flex, display: grid and display: inline-grid.

这同样适用于display:inline-flex,display:grid和display:inline-grid。

.box {
  border: 1px solid red;
  width: 100px;
  height: 100px;
  display: flex; /* new */
}
.center {
  background: blue;
  width: 50px;
  height: 50px;
  margin: auto;
}
<div class="box">
  <div class="center"></div>
</div>

#5


3  

It's because of the actual possibility of knowing the true height of the element in which you want to center vertically in. To understand that, first think about how auto horizontal centering works. You have a div which you've given it a width (fixed or percentage). The width can be calculated to certain degree. If it's fixed width, great. If it's flexible or responsive (percentage) at least you have a range that the width will cover before it hits the next breakpoint. You take that width, minus whatever it's inside and split the remainder on both sides.

这是因为实际可能知道要垂直居中的元素的真实高度。要理解这一点,首先要考虑自动水平居中的工作原理。你有一个div,你给它一个宽度(固定或百分比)。可以在一定程度上计算宽度。如果是固定宽度,很棒。如果它的灵活性或响应性(百分比)至少你有一个范围,宽度将在它到达下一个断点之前覆盖。你取宽度,减去它内部的任何宽度,然后将两边的剩余部分分开。

Now, with that information, how could the browser calculate the infinite amount of variations in which your div will grow vertically? Keep in mind the size of the element, wrapping of text, paddings, and responsiveness will also alter the width and force the text to wrap further, and on, and on it goes.

现在,有了这些信息,浏览器如何计算div将垂直增长的无限变化量?请记住元素的大小,文本的包装,填充和响应性也会改变宽度并强制文本进一步包装,然后打开,然后继续。

Is it an impossible task? Not really, has CSS spent time and effort covering this? Not worth their time, I guess.

这是一项不可能的任务吗?不是真的,CSS花费了时间和精力来解决这个问题吗?我猜不值得他们的时间。

And that is basically the answer I tell my students.

这基本上就是我告诉学生的答案。

But....fret not! Bootstrap v4 alpha has figured out vertical centering!

但是......不要担心! Bootstrap v4 alpha已经找到了垂直居中!

EDIT

编辑

Sorry to edit this late but I thought you may want to consider this solutions to center vertically and it is pretty simple by making use of the calc function

很抱歉编辑这个很晚但我觉得你可能想要考虑这个解决方案垂直居中,通过使用calc函数非常简单

<div class="foo"></div>

.foo {
  background-color: red;
  height: 6em;
  left: calc(50% - 3em);
  position: absolute;
  top: calc(50% - 3em);
  width: 6em;
}

See it HERE

在这看到它

#1


33  

As mentioned, this behavior is specified in section 10.6.2 of CSS2.1, and has remained unchanged from CSS2.

如上所述,此行为在CSS2.1的第10.6.2节中指定,并且与CSS2保持不变。

Block boxes are stacked vertically from top to bottom in normal flow. Furthermore, vertical margins may collapse, and only do so under certain circumstances (in your demo, the border on the parent element will prevent any margins on the child element from collapsing with its own). If you only have one such block box, and the height of the containing block is auto, then its top and bottom margins will be zero anyway. But if you have more than one block box in the same flow, or even out-of-flow boxes affecting the layout of in-flow boxes (in the case of clearance for example), how would you expect auto margins to resolve for those in-flow boxes?

在正常流动中,块箱从顶部到底部垂直堆叠。此外,垂直边距可能会崩溃,并且只在某些情况下才会崩溃(在演示中,父元素上的边框将阻止子元素上的任何边距与其自身折叠)。如果你只有一个这样的块盒,并且包含块的高度是自动的,那么无论如何它的顶部和底部边距都将为零。但是,如果在同一流程中有多个块框,或者甚至是影响流入框布局的流出框(例如,在清除的情况下),您会如何期望自动边距为这些框解决流入箱?

This is why auto left and right margins are likewise zeroed out for inline elements (including atomic inlines) and floats (though horizontal margins never collapse). Inline-level boxes are laid along line boxes, and floats too obey unique layout rules.

这就是为什么自动左右边距同样归零为内联元素(包括原子内联)和浮点数(尽管水平边距永不崩溃)。内联级框沿线框放置,浮动也遵循独特的布局规则。

Absolutely positioned boxes are a different story: since they are never aware of any other boxes in the same positioning context as themselves, auto top and bottom margins can be calculated for them with respect to their containing blocks without having to worry about any other boxes ever interfering.

绝对定位的盒子是一个不同的故事:因为他们从来没有意识到与自身相同的定位环境中的任何其他盒子,所以可以针对它们的包含块计算自动顶部和底部边距,而不必担心任何其他盒子干扰。

Flexbox is also a different story: what sets flex layout apart from block layout is that flex items are by definition always aware of other flex items in the same flex formatting context, including the fact that there are none. In particular, neither can floats intrude into the flex container, nor can you float flex items to subvert this (although you can still remove a child element from flex layout completely with absolute positioning). Margins behave very differently with flex items due in part to this. See sections 4.2, 9.5 and 9.6.

Flexbox也是一个不同的故事:将flex布局与块布局区分开来的是,Flex项目根据定义始终知道同一个flex格式化上下文中的其他flex项目,包括没有的事实。特别是,既不能浮动进入弹性容器,也不能浮动弹性项来破坏它(尽管你仍然可以通过绝对定位完全从弹性布局中移除子元素)。由于部分原因,边距与弹性项目的表现非常不同。见4.2,9.5和9.6节。

#2


29  

Why...because the W3C spec says so.

为什么......因为W3C规范是这样说的。

If 'margin-top', or 'margin-bottom' are 'auto', their used value is 0.

如果'margin-top'或'margin-bottom'为'auto',则其使用值为0。

As to the actual "why"...the query should really be addressed there.

至于实际的“为什么”...这个问题应该真正解决。

#3


16  

It doesn't center the element vertically because it is a block-level element in the normal flow. Thus, the following rule applies:

它不会垂直居中元素,因为它是正常流程中的块级元素。因此,以下规则适用:

If margin-top, or margin-bottom are auto, their used value is 0.

如果margin-top或margin-bottom为auto,则其使用值为0。

It's also worth pointing out that the rule above also applies to the following elements as well: (see points 10.6.2 and 10.6.3 for more information and conditions).

值得指出的是,上述规则也适用于以下要素:(有关更多信息和条件,请参见第10.6.2和10.6.3节)。

  • Inline replaced elements
  • 内联替换元素
  • Block-level replaced elements in normal flow
  • 正常流程中的块级替换元素
  • inline-block replaced elements in normal flow
  • 内联块在正常流程中替换了元素
  • Floating replaced elements
  • 浮动替换元素
  • Block-level non-replaced elements in normal flow when overflow computes to visible
  • 溢出计算为可见时,正常流程中的块级非替换元素

With that being said, absolutely positioned, non-replaced elements that don't have top, height, and bottom values of auto are an exception to this rule. The following applies from point 10.6.4:

话虽如此,绝对定位,没有顶部,高度和底部值auto的非替换元素是此规则的一个例外。以下适用于第10.6.4点:

If none of the three top, height, and bottom are auto and if both margin-top and margin-bottom are auto, solve the equation under the extra constraint that the two margins get equal values.

如果三个顶部,高度和底部都不是自动的,并且如果margin-top和margin-bottom都是auto,则在额外约束条件下求解等式,即两个边距得到相等的值。

See the example below demonstrating how an absolutely positioned element is vertically centered using margin: auto. It works because none of the three properties top, height, and bottom have a value of auto:

请参阅下面的示例,演示绝对定位元素如何使用margin:auto垂直居中。它的工作原理是因为top,height和bottom这三个属性都没有auto值:

.box {
  border: 1px solid red;
  width: 100px;
  height: 100px;
  position: relative;
}
.center {
  background: blue;
  width: 50px;
  height: 50px;
  margin: auto;
  position: absolute;
  top: 0; right: 0;
  bottom: 0; left: 0;
}
<div class="box">
  <div class="center"></div>
</div>

In addition, it's probably worth pointing out the following rule as well:

此外,它可能值得指出以下规则:

If one of margin-top or margin-bottom is auto, solve the equation for that value. If the values are over-constrained, ignore the value for bottom and solve for that value.

如果margin-top或margin-bottom中的一个是auto,则求解该值的等式。如果值过度约束,则忽略bottom的值并求解该值。

This means that if the absolutely positioned element has a margin-top value of auto and a margin-bottom value of 0 (i.e., margin: auto auto 0), the element would be absolutely positioned at the bottom relative to the parent like in the example below:

这意味着如果绝对定位元素的margin-top值为auto且margin-bottom值为0(即margin:auto auto 0),则该元素将绝对位于相对于父元素的底部,如示例如下:

.box {
  border: 1px solid red;
  width: 100px;
  height: 100px;
  position: relative;
}
.center {
  background: blue;
  width: 50px;
  height: 50px;
  margin: auto auto 0;
  position: absolute;
  top: 0; right: 0;
  bottom: 0; left: 0;
}
<div class="box">
  <div class="center"></div>
</div>

#4


13  

Why doesn't margin:auto work vertically?

为什么没有保证金:自动垂直工作?

Actually, it does – just not for every display value.

实际上,它确实 - 只是不是每个显示值。

If display is flex, margin: auto centers both vertically and horizontally.

如果显示为flex,则margin:auto垂直和水平居中。

The same applies to display: inline-flex, display: grid and display: inline-grid.

这同样适用于display:inline-flex,display:grid和display:inline-grid。

.box {
  border: 1px solid red;
  width: 100px;
  height: 100px;
  display: flex; /* new */
}
.center {
  background: blue;
  width: 50px;
  height: 50px;
  margin: auto;
}
<div class="box">
  <div class="center"></div>
</div>

#5


3  

It's because of the actual possibility of knowing the true height of the element in which you want to center vertically in. To understand that, first think about how auto horizontal centering works. You have a div which you've given it a width (fixed or percentage). The width can be calculated to certain degree. If it's fixed width, great. If it's flexible or responsive (percentage) at least you have a range that the width will cover before it hits the next breakpoint. You take that width, minus whatever it's inside and split the remainder on both sides.

这是因为实际可能知道要垂直居中的元素的真实高度。要理解这一点,首先要考虑自动水平居中的工作原理。你有一个div,你给它一个宽度(固定或百分比)。可以在一定程度上计算宽度。如果是固定宽度,很棒。如果它的灵活性或响应性(百分比)至少你有一个范围,宽度将在它到达下一个断点之前覆盖。你取宽度,减去它内部的任何宽度,然后将两边的剩余部分分开。

Now, with that information, how could the browser calculate the infinite amount of variations in which your div will grow vertically? Keep in mind the size of the element, wrapping of text, paddings, and responsiveness will also alter the width and force the text to wrap further, and on, and on it goes.

现在,有了这些信息,浏览器如何计算div将垂直增长的无限变化量?请记住元素的大小,文本的包装,填充和响应性也会改变宽度并强制文本进一步包装,然后打开,然后继续。

Is it an impossible task? Not really, has CSS spent time and effort covering this? Not worth their time, I guess.

这是一项不可能的任务吗?不是真的,CSS花费了时间和精力来解决这个问题吗?我猜不值得他们的时间。

And that is basically the answer I tell my students.

这基本上就是我告诉学生的答案。

But....fret not! Bootstrap v4 alpha has figured out vertical centering!

但是......不要担心! Bootstrap v4 alpha已经找到了垂直居中!

EDIT

编辑

Sorry to edit this late but I thought you may want to consider this solutions to center vertically and it is pretty simple by making use of the calc function

很抱歉编辑这个很晚但我觉得你可能想要考虑这个解决方案垂直居中,通过使用calc函数非常简单

<div class="foo"></div>

.foo {
  background-color: red;
  height: 6em;
  left: calc(50% - 3em);
  position: absolute;
  top: calc(50% - 3em);
  width: 6em;
}

See it HERE

在这看到它