When absolute positioning an element using top
, right
, bottom
and left
you're moving it a certain distance from that elements edges. It will move it in relation to the last positioned element. The last position element is the next ancestor element that has any type of positioning applied to it via CSS. If no ancestor element as positioning set then the viewport window will be used as a reference.
I created a quick diagram to show what is going on.

left: 50%;
moves the element's left edge 50% (half) of the width of the last positioned element's left edge. You're effectively moving elements to the right by adding space between element left edges.
margin-left: <negative value>;
is set to half the element's width pulling it back to the left. This fixes the off center issue you're seeing.
Today a lot of people will forgo using margin-left
with a negative value and opt for transform: translateX( -50% );
. This allows them to be more flexible as the elements width does not need to be known.
The CSS for transform: translateX( -50% );
might look like this:
div {
position: absolute;
left: 50%;
border: 2px dashed red;
width: 200px;
height: 100px;
transform: translateX( -50% );
}
Demo JSFiddle.
If you're looking to simply center something horizontally and you have applied a width (px
, %
, etc. work) then you can use margin: 0 auto; width: <width value>;
. A width must be set for margin: 0 auto;
to work!
Example:
div {
margin: 0 auto;
width: 25%;
height: 100px;
border: 2px dashed red;
}
Demo JSFiddle.