Centering Absolutely Positioned Elements With Unknown Width
Time to put your seatbelts back on, IE's expanding shrink wrap bug is here to hunt us again.
Example 6
LoremIpsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum Lorem Ipsum
Lorem Ipsum! Lorem Ipsum!
HTML Code
<div id="container">
<div class="outer">
<div class="inner">
<p>
LoremIpsum Lorem Ipsum
Lorem Ipsum Lorem Ipsum
Lorem Ipsum Lorem Ipsum
Lorem Ipsum Lorem Ipsum
Lorem Ipsum Lorem Ipsum
Lorem Ipsum Lorem Ipsum
Lorem Ipsum Lorem Ipsum
Lorem Ipsum<br>
<img src="smiley.png"
alt="Lorem Ipsum" width="35" height="35">
</p>
</div>
</div>
<div class="outer2">
<div class="inner">
<p>
Lorem Ipsum!
Lorem Ipsum!<br>
<img src="smiley.png"
alt="Lorem Ipsum" width="35" height="35">
</p>
</div>
</div>
</div>
CSS code
#container
{
height: 200px;
position: relative;
overflow: hidden;
}
.outer, .outer2
{
position: absolute;
top: 0;
width: 200%;
left: -50%;
}
.outer2 { top: 85px; }
.inner
{
position: absolute;
left: 50%;
}
.inner p
{
position: relative;
left: -50%;
}
.outer2 p
{
background: #afa;
}
<!--[if IE]>
<style type="text/css">
.inner p { float: left; }
</style>
<![endif]-->
The method is extremely familiar to method of centering floats. However, there may seem to be some redundant or unexpected code, .outer, .outer2 { width: 200%; } in particular.
First of all it's important to understand the difference on how left and right properties affect absolutely and relatively positioned elements.
When position property is set to value relative, code left: 50% will offset the entire element by 50% of the width of the parent container. However, when the position property is set to absolute and width is set to auto (the default width value), left: 50% will move the left margin edge of the element by 50% of the width of the container, i.e. resizing the element.
So what problem does it create to us? If we would to try to center our absolutely positioned element the same way we centered floats subsequently changing position: relative to position: absolute, our "shrink-wrapped" element would be able to expand only up to the half of its parent. If that's good enough for you, you can avoid the second wrapper <div> in the example above.
With obstacles addressed, let's begin breaking down the code and looking at what it does. Once again, #container
{ position: relative; } establishes containing block for our absolutely positioned elements. However, note the #container { overflow: hidden; } it not there to contain any floats as one may think at first. It does exactly that, hides any overflow. Where is that overflow coming from? Take a guess, it's from .outer, .outer2 { width: 200%; } which makes .outer and .outer2 twice as wide as the parent, but #container { overflow: hidden; } hides that extra half of width.
Now, let's follow the "tree" of our left property values on all those container and see each step's purpose.
Along with doubled width, our .outer also has left: -50%; (note the minus sign). Since we did define width, left moves the entire element to the right (because we have used a negative value for left), half the parent's width. Now the horizontal middle of .outer is in the center of #container with 25% of .outer's width (remember, we doubled the width) sticking out of the #container on each side. If you don't understand why 25% on each side, let me follow again on our dimensions. .outer's width is double the parent's width, left: -50% moved .outer half of the parent's width which is exactly 25% of .outer's width. Since originally .outer's left edge was at the left edge of the #container and we moved it 25% of .outer's width the other 25% of .outer's width will end up sticking out on the other side of #container. What we basically did is created a centered container which is double the width of the #container and if you were following the above paragraphs you know why we wanted this - our shrink wrapped element will expand only half the width of that parent, but since we have just doubled the width of the parent, the shrink wrapped element will be able to expand up to 100% of the #container.
Next step is absolutely positioned .inner with left: 50% on it (note that this time it is a positive value). Since .inner does not have any width set (i.e. has width: auto since that's the default), left: 50% moves the left margin edge of .inner to the center of .outer consequently allowing the shrink-wrapped contents of .inner to expand only up to the half of .outer's width, but since we have doubled .outer's width, this effect is exactly what we want.
Final step is the actual element which we were trying to center in the first place, is our .inner p. Note that it is relatively positioned (i.e. has position: relative) and the reason is that we want left: -50% (negative value again) to offset the element itself instead of only its margin edge. Now .inner's left margin edge is in the center of .outer (and of course the center of #container) as well as .inner is shrink wrapped around our <p> thus <p>'s left margin edge is in the center of #container. Offsetting <p> by half the .inner's width is the same thing as offsetting it by the half of its own width which will perfectly center it inside #container which is what we wanted.
back to top