hasLayout.net

Vertical Centering

Description

Various methods for CSS vertical centering

Date of the Tutorial

Sat Aug 15 22:51:47 2009

Overview

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.

Images In Text - Vertical-Align

Before we begin with "real stuff". I'd like to demonstrate this example of vertically centering images when they appear in text:

Lorem Ipsum CAN HAS VERTICAL CENTER?
HTML Code:
<p>
    <img src="/pics/smiley.png" alt="Lorem Ipsum" height="35" width="35">
    CAN HAS VERTICAL CENTER?
</p>
CSS Code:
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.

Single-Line Inline Content Inside Fixed Height Container - Line-Height Method

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:

CAN HAS VERTICAL CENTER?
Lorem Ipsum CAN HAS VERTICAL CENTER?
HTML Code:
<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>
CSS Code:
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.

Fixed Height Absolutely Positioned Element Inside Fixed Height Container

CAN HAS VERTICAL CENTER?

HTML Code:
<div>
    <p>CAN HAS VERTICAL CENTER?</p>
</div>
CSS Code:
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.

Fixed Height Block-Level Element Inside Fixed Height Container

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?

HTML Code:
<div>
    <p>CAN HAS VERTICAL CENTER?</p>
</div>
CSS Code:
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 borders 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).

Dynamic Height Block-Level Element Inside Dynamic Height Container

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:

foo bar baz
foo bar baz
foo bar baz
foo bar baz
foo bar baz
foo bar baz
foo bar baz
foo bar baz
foo bar baz
foo bar baz

CAN HAS VERTICAL CENTER?

HTML Code:
<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>
CSS Code:
#container {
    display: table;
    width: 100%;
}
    #dynamic_height_giver {
        display: table-cell; 
        width: 200px;
        background: #0d0;
    }
    #middle {
        display: table-cell;
        vertical-align: middle;
    }
Conditional Comments Code:
<!--[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 floating 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.

Final Words

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.