Description
Various methods for CSS vertical centering
Date of the Tutorial
Sat Aug 15 22:51:47 2009
Various methods for CSS vertical centering
Sat Aug 15 22:51:47 2009
Vertical centering with CSS seems to be a large obsticle in the Web design world and I notice a lot of people favor ' element"><table>
-based layouts when the need for vertical center arises. That's too bad.
Whilst CSS vertical center can get [very] complicated at times, I believe that learning various techniques for archiving it is beneficial and once you get a hang of it, you'll do it just as anything else with CSS.
Before we begin with "real stuff". I'd like to demonstrate this example of vertically centering images when they appear in text:
<p> <img src="/pics/smiley.png" alt="Lorem Ipsum" height="35" width="35"> CAN HAS VERTICAL CENTER? </p>
img { vertical-align: middle; }
Normally, that image would be "sitting" on the same line as the text, which may or may not be what you are looking for. We used vertical-align
property to center the image: img { vertical-align: middle; }
. Pretty simple, isn't it?
I often see people who expect vertical-align
property to be the almighty axe and wonder why their ' element"><div>
is not centered by it. Let me quote the spec for this property: Applies to: inline-level and 'table-cell' elements
(vertical-align
property). What this means is that using vertical-align
property will center only the inline-level elements (or the ones on which display
was set to value inline
. The spec also mentions table-cell
elements, but I'll be getting to that a bit later in this tutorial.
To start off with the basics, let's cover the line-height
centering method. This method is applicable to one-line pieces of text or images; it's very simple to grasp and is quite cross-browser [almost] without extra hacks
. Let's have a look:
<p>CAN HAS VERTICAL CENTER?</p> <p> <img src="/pics/smiley.png" alt="Lorem Ipsum" height="35" width="35"> <span class="for_ie6"></span> CAN HAS VERTICAL CENTER? </p>
div { height: 100px; line-height: 100px; white-space: nowrap; } img { vertical-align: middle; } .for_ie6 { display: inline-block; } .for_ie6 { display: inline; }
In the first example we only have text. The container of that text has height
set to value 100px
and that's the exact same value to which we set line-height
property; this is what makes the text centered. You'll also notice that I've used white-space
property set to value nowrap
. While you probably won't see this bit used in many of other resources on this method of centering, I tend to always include it. Why? Since we altered line-height
to be so large, should that text wrap on the next line (due to user specified font-size
or other reasons) the second line would be 100px
apart from the first. This is the reason why this method is only useful for single line of text or a simple inline-level element.
CAN HAS VERTICAL CENTER?
<div> <p>CAN HAS VERTICAL CENTER?</p> </div>
div { position: relative; height: 200px; } p { position: absolute; top: 50%; height: 50px; margin-top: -25px; }
The containing element - ' element"><div>
- has position: relative;
set on it for the sake of our ' element"><p>
element offsets to be relative to it. It also has height
set on it; although unless you are supporting this method can be used to vertically center our ' element"><p>
when the containing ' element"><div>
has height that is defined by the content.
The method is simple: we have set top
property on our absolutely positioned element to value 50%
; this would position the very top of the ' element"><p>
right in the middle of our ' element"><div>
. We are also setting margin-top
to value -25px
, that value is half of the height
set on the ' element"><p>
; doing so moves the ' element"><p>
element half of its height up. Since before that, its top edge was in the middle of the ' element"><div>
, now its center is in the middle.
At first, I was hesitant to include this example in this tutorial, but I thought it won't hurt because beginners may not find the solution to be that obvious or may not know about collapsing margins.
CAN HAS VERTICAL CENTER?
<div> <p>CAN HAS VERTICAL CENTER?</p> </div>
div { height: 200px; } p { height: 50px; margin-top: 75px; }
This method is only applicable if you have set height
on both the container and the element you're trying to center using the same units - in our case it's pixels. Simple method, what I did is set margin-top
on our ' element"><p>
element to the value that would make it look vertically centered. I've calculated the value as follows: half the height of the container minus half the height of our ' element"><p>
element. What you may run into with this method is collapsing margins - the margin
on ' element"><p>
transfering onto ' element"><div>
(that's not what collapsing margins about exactly, but that what it may look to you like if you're new). In my demo, margins are no collapsing due to border
s set on elements. If you are having trouble figuring out how to uncollapse your margins, have a read on CSS Specification on collapsing margins as well as this tutorial on uncollapsing margins (that I admittedly never read, but it get links to a lot in #css IRC channel).
This method is actually more functional in IE7 than in sane browsers, can you believe it? With this method you can center a dynamic-height block-level element inside a dynamic-height container. The reason I say that it's more functional in IE7 is that in sane browsers you may run into width problems as the method gives off side effects; for example, in aforementioned IE versions you can have the "foo bar baz" div to be of shrink-wrap width, whilst I couldn't figure out a way to have that in sane browsers. Anyway, let's first take a look at the demo and the code:
CAN HAS VERTICAL CENTER?
<div id="container"> <div id="dynamic_height_giver"> foo bar baz<br> foo bar baz<br> foo bar baz<br> foo bar baz<br> foo bar baz<br> foo bar baz<br> foo bar baz<br> foo bar baz<br> foo bar baz<br> foo bar baz<br> </div> <div id="middle"> <div id="ie_helper"> <p>CAN HAS VERTICAL CENTER?</p> </div> </div> </div>
#container { display: table; width: 100%; } #dynamic_height_giver { display: table-cell; width: 200px; background: #0d0; } #middle { display: table-cell; vertical-align: middle; }
<!--[if lte IE 7]>
<style type="text/css">
#dynamic_height_giver {
float: left;
}
#middle {
position: relative;
top: 50%;
}
#ie_helper {
position: relative;
top: -50%;
}
#middle,
#ie_helper,
#container p {
zoom: 1;
}
* html #dynamic_height_giver {
margin-right: -3px;
}
</style>
<![endif]-->
NOBODY PANIC! This may seem like a ton of code, but a lot of it is the just the setup and a few IE hacks that are not relevant to centering. Let's take it one step at a time.
I suggest you read the entire CSS2.1 Specification Chapter 17 - Tables before we continue; it's useful even if you just glance over it.
Here we go! First off, let's move the stuff not relevant to centering out of the way first. I am talking about #dynamic_height_giver
div and every style that applies to it. It's just there for the #container
to have some dynamic height in which we would vertically center our ' element"><p>
element. The only thing that you may want to note here is that I am giving it { display: table-cell; }
in sane browsers and float
ing it for IE7. The reason why I am using different methods here is because if we float
#dynamic_height_giver
, sane browsers would do the whole table-cell positioning/computation voodoo and our ' element"><p>
would be positioned not the way we want it [horizontally].
Let's see what we are doing for sane browsers and go over IE7 afterwards. We are setting display
property to value table
on #container
and table-cell
on #middle
. The reason for table
on #container
is to make our - now a table-cell - #middle
stretch out in height to fill the #container
. If you recall from the first example, vertical-align
applies to table-cell elements as well. However, this time, appying it on our #middle
will make #middle
's content, even block-level elemens, vertically centered inside of it. Since due to { display: table }
the #middle
is vertically stretched to fill the entire #container
, putting all the stuff in #middle
vertically centered makes it also vertically centerd in #container
- exactly what we wanted. IE8 supports table*
display
property values, thus our IE fixes will only apply to IE7 - I've used conditional comments, but feel free to use ugly hacks instead.
Now, let's see what we are doing to make it all work in IE7. Since these versions of IE do not support table*
display
property values, we have to hack around it. Luckly, both of these versions of IE have a bug in them. This bug involves percentage values for top
property when position
property is set to value relative
to be still computed according to dynamic height of the container. Magnificent, isn't it? The way we will fix it resembles Fixed Height Absolutely Positioned Element Inside Fixed Height Container example described above. We will need an extra element; the reason I have that #ie_helper
' element"><div>
inside #middle
. Keeping that bug in mind, we are moving #middle
's top edge into the middle of #container
with { position: relative; top: 50%;
} set on it. Now we have to move it back up to half the height of our original element that we are trying to center - the ' element"><p>
. We accomplish that using #ie_helper
by setting { position: relative; top: -50%; }
on it. Since #ie_helper
's height depends on our ' element"><p>
it is the same as ' element"><p>
's height - using the bug, we did exactly what we just needed.
I hope that methods as well as description of what is going on provided in this tutorial will help you on your vertical-center virtues that were not described in this tutorial.
After a couple of years of chilling on IRC #css help channel, I noticed that a lot of people seem to be looking for "dead center" methods - centering vertically and horizontally. All I will do is point you to my Horizontal Centering tutorial in hope that using this tutorial along with it you'll gain enough knowledge to combine both axis center. Also, see my example of dynamic width/height center example along with reisio's simple deadcenter example.