Why don't margin-top: auto and margin-bottom:auto work the same as their left and right counterparts?
The short answer is the spec says so.
10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements
If 'margin-top', or 'margin-bottom' are 'auto', their used value is 0.
http://www.w3.org/TR/CSS2/visudet.html#Computing_heights_and_margins
Is there any difference between margin: 0 auto; and margin: auto;
Yes.
margin: 0 auto;
Sets the element's left and right margins to auto
, and the top and bottom margins to 0
.
margin: auto;
Sets all the margins to auto
. You are probably getting the same behaviour due to your <body>
being 100% height, hence the vertical auto
margins have no effect.
What, exactly, is needed for margin: 0 auto; to work?
Off the top of my head:
- The element must be block-level, e.g.
display: block
ordisplay: table
- The element must not float
- The element must not have a fixed or absolute position1
Off the top of other people's heads:
- The element must have a
width
that is notauto
2
Note that all of these conditions must be true of the element being centered for it to work.
1 There is one exception to this: if your fixed or absolutely positioned element has left: 0; right: 0
, it will center with auto margins.
2 Technically, margin: 0 auto
does work with an auto width, but the auto width takes precedence over the auto margins, and the auto margins are zeroed out as a result, making it seem as though they "don't work".
margin: auto auto
Ultimately it's a w3c spec -
If 'margin-top', or 'margin-bottom' are 'auto', their used value is 0.
It does seem like it would be handy.
Regarding margin property and value auto
Vertical alignment in Css is such a fun and painful topic. This stackoverflow queston is the best concise explanation I have seen regarding why vertical alignment can be so painful
As to your 1st question, the reason you can't vertically align using margins is explained below in the quote.
... the nature of document flow and element height calculation algorithms make it impossible to use margins for centering an element vertically inside its parent. Whenever a vertical margin value is changed, it will trigger a parent element height re-calculation (reflow), which would in turn trigger a re-center of the original element... making it an infinite loop.
As to your 2nd question, margin auto achieves horizontal centering by calculating the width of the child container in relation to its parent's width. Then it does simple math to add an even amount of margin to the left and right of the child container, enforcing horizontal centering.
As for 2nd question Part B,
margin: auto
is the same as the following:
margin-top: auto;
margin-bottom: auto;
margin-right: auto;
margin-left: auto;
where as margin: 0 auto
is the equivalent to the following:
margin-top: 0;
margin-bottom: 0;
margin-right: auto;
margin-left: auto;
A solution to achieve vertical centering
There are some options that you can utilize however to achieve vertical alignment despite the limitations. The easiest is to leverage a table. With tables, one of the few strong points of them is that using the vertical-align
property actually behaves as you would expect when enforced inside of a table. So you can do something like the following:
<body>
<table style="width: 100%; height: 100%">
<tr>
<td>
<div id="verticallyCenteredContent" style="vertical-align: middle">
OMG it's vertically aligned
</div>
<td>
<tr>
<table>
<body>
There are two other common methods that I demonstrated in this jsfiddle.
Useful article that demonstrates a number of scenarios and approaches for achieving vertical centering - Vertical Centering with Css
Cheers!
Invalid property value for margin-left: auto
margin-left
cannot have multiple arguments. unlike margin
. so margin-left: 0 auto
is invalid as 0
and auto
are two separate arguments, while margin: 0 auto
is valid as this is shorthand for
margin-top: 0;
margin-bottom: 0;
margin-left: auto;
margin-right: auto;
These are applied in a clockwise order, so if you do margin: 12px, 13px, 14px, 15px;
the margins would be applied to the top, right, bottom, and left items respectfully.
Read more about it here.
Why does margin: auto only work horizontally and not vertically?
It's really less of a nightmare than you think, just don't use margins. vertical-align
is really what you should rely on for fluid-height vertical centering. I threw together a quick demo to demonstrate my point:
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
text-align: center;
}
span {
height: 100%;
vertical-align: middle;
display: inline-block;
}
#any-height {
background: #000;
text-align: left;
width: 200px;
height: 200px;
vertical-align: middle;
display: inline-block;
}
<span></span>
<div id="any-height"></div>
Why doesn't margin: auto center an element vertically?
As mentioned, this behavior is specified in section 10.6.2 of CSS2.1, and has remained unchanged from 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.
Related Topics
Tools Debugging CSS in Internet Explorer
How to Hack Unsupported Mix-Blend-Mode CSS Property
In Firebug, How to Tell What Is Overriding a Style
Browser as a Design Tool - Change Colors, Save Them
Change Link Color on Div Hover
Angular Material Md-Datepicker Inside Bootstrap Modal
Scale an Image to Maximally Fit Available Space and Center It
Multiple Background Images Using SASS/Compass
Wobbly CSS Animation with Border-Radius in Internet Explorer
Is -Negative Margin or Padding Invalid CSS According to W3C
How to Add Multiple Linear-Gradients to a CSS Background
CSS: Using Hsl Variable in Hsla
Why Do 'Inline-Block' Elements Auto-Clear Their Children