Why magin:auto is not enough to center position absolute or fixed?
Solution 1:
You need to refer to the specification to understand this. If your element is not positionned using position:absolute
then you need to consider this section where you can read:
If both 'margin-left' and 'margin-right' are 'auto', their used values are equal. This horizontally centers the element with respect to the edges of the containing block.
For in-flow elements, only margin is needed in addition to the width.
When it comes to position:absolute
elements we refer to this section
If all three of 'left', 'width', and 'right' are 'auto': First set any 'auto' values for 'margin-left' and 'margin-right' to 0
It's clear that if you don't see any left, right or width, margin will get computed to 0
(no centring)
If none of the three is 'auto': If both 'margin-left' and 'margin-right' are 'auto', solve the equation under the extra constraint that the two margins get equal values
When you set left, right and width the margin will get equal values (that we can found with the formula) and you will have centring.
If you continue reading you can also see:
Otherwise, set 'auto' values for 'margin-left' and 'margin-right' to
0
, and pick the one of the following six rules that applies.
So we only get a centring effect for margin if we set left, right and width. omiting one will not center the element.
Below an example to illustrate the 8 different cases like detailed in the specification.
.box {
height:50px;
border:1px solid;
position:relative;
margin:5px;
}
.box > div {
position:absolute;
left:0;
right:0;
margin:auto;
width:200px;
background:red;
color:#fff;
}
<div class="box">
<div>some text</div>
</div>
<div class="box">
<div style="width:auto;">some text</div>
</div>
<div class="box">
<div style="left:auto">some text</div>
</div>
<div class="box">
<div style="left:auto;width:auto">some text</div>
</div>
<div class="box">
<div style="right:auto">some text</div>
</div>
<div class="box">
<div style="right:auto;width:auto;">some text</div>
</div>
<div class="box">
<div style="right:auto;left:auto;">some text</div>
</div>
<div class="box">
<div style="right:auto;left:auto;width:auto;">some text</div>
</div>
Worth to note that you don't necessarely need 0
but you need to specify any value different from auto
which is the same for left and right.
.box {
height:50px;
border:1px solid;
position:relative;
margin:5px;
}
.box > div {
position:absolute;
left:0;
right:0;
margin:auto;
width:200px;
background:red;
color:#fff;
}
<div class="box">
<div>some text</div>
</div>
<div class="box">
<div style="left:10px;right:10px;">some text</div>
</div>
<div class="box">
<div style="left:-10px;right:-10px;">some text</div>
</div>
<div class="box">
<div style="left:50px;right:50px;">some text</div>
</div>
<div class="box">
<div style="left:300px;right:300px;">some text</div>
</div>
<div class="box">
<div style="left:3000px;right:3000px;">some text</div>
</div>
Of course, when both values are very big you will not get a center effect due to this rule:
..unless this would make them negative, in which case when direction of the containing block is 'ltr' ('rtl'), set 'margin-left' ('margin-right') to zero and solve for 'margin-right' ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto', solve the equation for that value. If the values are over-constrained, ignore the value for 'left' (in case the 'direction' property of the containing block is 'rtl') or 'right' (in case 'direction' is 'ltr') and solve for that value.
Almost the same is considered when it comes to the vertical direction (top, bottom and height): https://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-height