OverviewProcessServicesWorkBlog
DP Blog
10. 7. 2008
Search
View Our Keyword Cloud
(aka Tag Cloud)
Recent Posts
Archives
Syndicate RSS Feed
[Valid RSS]

CSS and Vertical Alignment

Even with all the 'warm fuzzies' that designers and developers alike get by keeping our markup separate from design, conforming to web standards, and getting cross-browser compatible CSS driven layouts out the door, there are still some days when we want to curse the CSS gods and go back to the comfort and predictability of tables. And of course it's always raining on those days. Just like yesterday. Even so, I found two viable solutions to the vertical alignment problem that has been plaguing us CSS geeks from the beginning.

True, CSS2 has the vertical-align attribute but it doesn't always work the way one would expect. The vertical align attribute is only applied to inline elements, such as images, or table-cell elements not block level elements (learn more about block vs. inline). So what if you wanted to vertically align a block level element, such as a div?

After some perusing of the CSS community, I found a few different solutions to this problem, however most solutions called for the knowledge of the height of the outer container and inner container which you are trying to align. But in real world development, how often do we know how tall our content is going to be? Or how tall the outer container is, especially if this outer container is the browser window? It seems these solutions do not allow for much flexibility. So I set out to try and figure out a way to vertically align a container within the browser. After some trial and error with CSS alone, I decided it was time to bring in the power of the Document Object Model (DOM) in order to find a suitable solution. Using DOM, we can find the height of our containers even if they are dynamic. For instance, to get the html body height and the height of the container I want to align I would do the following:

    bodyHeight = document.defaultView.getComputedStyle(document.body, null).getPropertyValue("height");
    containerHeight= document.defaultView.getComputedStyle(document.getElementById(divName), null).getPropertyValue("height");
    //trim off 'px'
    bodyHeight = String(bodyHeight).substring(0,bodyHeight.length - 2);
    siteHeight = String(siteHeight).substring(0,siteHeight.length - 2);

Once I have these values, I can use some basic math (I suppose I can't say I never use what I learned in high school anymore) to add the appropriate amount of top-padding to vertically align my element. Note, I only vertically align the container if it is smaller than the browser. Otherwise I simply use a default top padding.

    if(siteHeight < bodyHeight){
        topPadding = (Number(bodyHeight) - Number(siteHeight))/2;
        document.getElementById(divName).style.paddingTop= topPadding + 'px';
    }else{
       topPadding = defaultPadding;
       document.getElementById(divName).style.paddingTop= topPadding + 'px';
    }

Finally, I simply call the JS function that holds this code on window load and resize. This works beautifully except for one problem, the alignment does not occur until the window has finished reloading or resizing which can lead to some jumpiness of transition. Due to this awkward transition, I again decided to try and find a CSS/HTML only solution.

Thanks to this example of vertically centering at jakpsatweb, I was able to get it working via css. As mentioned previously, vertical-align not only applies to inline elements, but any element whose display is set to "table-cell". By forcing my block elements to use this display, I can now successfully use the vertical-align attribute. The html I used looks like:

<div id="siteTable">
    <div id="siteTableCell">
        <div id="contentContainer">
            <p>content goes here</p>
        </div>
    </div>
</div>

Then I set up my css. I want the body height to fill the browser, so I set html, body{min-height:100%;}. I set up my siteTable div to have a display:table and min-height of 100%, and finally I set my siteTableCell div to display:table-cell; margin: 0 auto; (to horizontally center); vertical-align:middle. This will vertically align any items inside the siteTable. Lastly, I add hacks for IE just as with the jakpsatweb example. My final CSS looks like this:

        html, body   {
             margin:0; //zero out margins & padding to prevent unnecessary vertical scroll
             padding:0;
             height:100%;
        }
        #siteTable{
            width:100%;
             height:100%;
            display:table;
            /*IE fix*/
            #position: relative;          
        }
         #siteTableCell {
            margin: 0 auto;
            width:100%;
            display:table-cell;
            vertical-align:middle; 
            /*IE fix*/
            #position: absolute; 
            #top: 50%;
            #left: -50%;    
        }
        #contentContainer{
            margin: 0 auto;
            display:block;
            width:800px;
            border:1px solid;
            min-height:450px;
            background-color:#ccc;
            /*IE fix*/
            #position: relative; 
            #top: -50%;
            #left: 50%;
        }
       * html #contentContainer{/*apply to IE6 but not IE7*/
          height: 450px
       }

And viola. Now we have a site vertically aligned to the browser window.

See live example at: http://www.d-p.com/templates/verticalAlignFinal.html

Comments (6)

E-mail this Blog to a Friend! Leave a Comment
  • >> This doesn’t work in IE 6 and 7 unless the comment is above the doctype, which I'm pretty sure causes quirks mode in those browsers. - paul
  • >> Good catch, Paul! I have updated both my post and the code to use the # IE hack as opposed to the * html hack. I have also removed the comment at the top of my html. That seems to do the trick. Thanks! - Colleen
  • >> Mo' better. Now however IE 6 & 7 give lengthy horizontal scroll bars. For IE hackage I prefer conditional comments - though for a tutorial perhaps not as brief. - paul
  • >> Hey Paul, I've fixed the horizontal scroll issue in IE by simply modifying which left positioning is negative (siteTableCell is now #left: -50%; while contentContainer is #left: 50%;) Again, updates in blog post & live html. Unfortunately this same method doesn't work for top positioning to solve the unnecessary vertical scroll. I'll keep you posted as soon as I find a solution. Thanks! - Colleen
  • >> you go girl. :) - paul
  • >> thanks for this hack!!! :) - pbmax
Your Name:
Your Email
Your Comments: