Why doesn’t “margin: auto” center an element vertically?

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

The question is not asking for workarounds.

.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>

solution

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.

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).

  • 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:

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.

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:

.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.

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:

.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>