Skip to Content
Skip to Navigation

Equal height columns with css

16 March 2009 - 10 comments

The search for a technique that offers real equal height columns leads nowhere because we don't have full vertical control in current CSS 2.1 implementations cross browser

This is how Ingo Chao start his article presenting a method to create a css-based layout with equal height columns. Having columns with equal heights is not something always easy to do if you only rely on CSS, and beside the Faux column method, I'm not aware of any stable way to create equal height columns using only CSS without any extra markup.

After some more research on the subject, the solutions I found were either buggy or complicated to implement, so I decided to experiment with all these methods to create a simple and flexible method, that would load the content before the sidebars, that could be either fluid, fixed or grid-like, and of course, work across all browsers.

I have to admit that I REALLY thought that I was inventing something, until I found this article from Paul O'Brien. His method uses the same positionning trick as the one I use for the columns.. My only real contribution would be to make a fusion of a holy-grail-like method with the O'Brien method. The final layout can be modified very easily, switched from fluid to fixed or grid-like on demand, loads the content before the sidebars (content->left->right), can be adapted to as many columns as you want, works on pretty much all browsers, and of course, simulate equal heights columns.

Quickly explained

Like the O'brien method, I use an extra <div> (I know, shame on me!) for each column. Then I position them absolutely and this is where the real magic is happening. A normal block with a height of 100% can only fill its container if the container itself have a height. But this doesn't apply if the block is positioned absolutely. So if I position the block to the bottom and give it a height of 100%, it creates a background for the column that will extend until the footer of the page. Do this for each column, and you end up with a layout with equal height column.

Here are some examples of the final layouts, and some HTML slides that present the method step by step.

The concept step by step

step 1
You start with a normal layout.
step 2
We won't be using the 'real' columns to have a background.
step 3
Instead, we add three <div> at the bottom of the page, that have the same class as their respective columns, so the <div> are aligned with their columns.
step 4
The <div> are positioned absolute.
step 5
Give each <div> a height of 100%, and positioning to the bottom creates the full-height columns.
step 6
Bring the content back up with z-index:2; and voilà !

A closer look at the code

here is the original markup I use. It could be a little bit lighter if you consider that IE is not worth worrying about, as #main is only used to fix a clearing issue.

  <div id="page">
    <div id="header">...</div>
    <div id="main">
      <div id="content">
        <div id="content-inner" class="column center">...</div>
      </div>
      <div id="left" class="column left">...</div>
      <div id="right" class="column right">...</div>
    </div> <!-- /main -->
    <div id="footer">...</div>
  </div><!-- /page -->

Here is a graphical representation of the <div>:

Divs

The base Layout

Let's have a closer look at how the layout is created. First of all, I always start with a simple browser reset.

  *{
    margin:0;
    padding:0;
  }

Then we can start setting up the layout. We add some colors to see what we're doing:

  #header, #footer{background-color: #ccc;}
  #left{background-color:#d7ecff;}
  #right{background-color:#daffc6;}
  #content-inner{background-color:#fff2d7;}

Setting up the width of the sidebars.

  .left {
    width: 220px;         
  }                        
  .right{                  
    width: 150px;         
  }

Then prepare the content to compensate for the sidebars once they are positioned correctly.

  #content-inner {
    margin-left: 220px; 
    margin-right: 150px;
  }

Bringing the sidebars back at the same level of the content, using the #content and by floating all columns.

  #content {
    float:left;
    width:100%;
    margin-right:-100%;
  }
  .column {
    float:left;
  }

A quick insurance for IE to work properly... un-floating the center column.

  #content-inner {
     float:none;
     margin-left: 220px; 
     margin-right: 150px;
   }

The right sidebar shouldn't be floating left, but right.

  .right{                 
    float:right;          
    width: 150px;
  }

Last touch, the footer should clear the columns. Plus some styles.

  #footer, #header{
    clear:both;
    text-align:center;
    font-size:2em;
  }

The layout is done, so you should have something like this. So far so good, it works across all browsers without any hacking. But you'll notice that all the column have a different height, and this is what we are now going to fix.

The Equal Height Columns

Firts, let's add the empty <div> (blush). Notice how we give the same class right, left or center to the empty <div> so they behave like their corresponding columns.

  <div id="page">
    <div id="header">...</div>
    <div id="main">
      <div id="content">
        <div id="content-inner" class="column center">...</div>
      </div>
      <div id="left" class="column left">...</div>
      <div id="right" class="column right">...</div>
    </div> <!-- /main -->

    <!-- These are used to create the columns background -->
    <div id="bgcenter" class="bg center"></div>
    <div id="bgleft" class="bg left"></div>
    <div id="bgright" class="bg right"></div>

    <div id="footer">...</div>
  </div><!-- /page -->

As these <div> are empty, you shouldn't notice any difference in your layout. In order to see our work, we are going to change the color rules to be applied on these empty <div>.

  #bgleft{background-color:#d7ecff;}
  #bgright{background-color:#daffc6;}
  #bgcenter{background-color:#fff2d7;}

Now that we have the colors applied on the futur 'fake columns', let's start the magic. First, as we are going to position the fake columns, and reset their relative element to the #page element.

  #page{
    position:relative;
  }

Now we can position the fake columns and give them a height. It is very important to position these at the bottom, for browser compatibility.

  .bg{
    position:absolute;
    bottom:0;
    height:100%;
  }

Then we can override these general rules for each column to position them correctly and with the right width.

  #bgleft{
    left:0;
  }
  #bgright{
    right:0;
  }
  #bgcenter{
    right:0;
    width:100%;
  }

Notice how we can give a width of 100% to the content as it's loaded before the other columns, so it'll show up under them. Now everything is fine, but the fake columns are showing up on top of the content... not good, so in order to bring the content back up, I just need to play with it's z-index of the content:

  #content, #left, #right, #header, #footer{
    position:relative;
    z-index:2;
  }

There you go! All columns appear to be the exact same height, and you can even style each one of them independently. But of course, as I said a little bit earlier, all versions of IE before version 8 need a little bit of tweaking. Nothing serious though... drop this in your <head> and it should fix it all !

  <!--[if lt IE 8]>
    <style type="text/css">
      /* Only Hack for IE */
      #main, #page{ height:1%; }
      .bg{ height:1000em; }    
    </style>
  <![endif]-->

I prepared some examples of this method, with fluid or fixed width, and even with a "fluid grid example". Except for the extra markup, the only drawback that I could think about this method is that the header and footer needs to be hiding the columns. It might be ok for simple projects, but maybe a little bit tricky for more complex layouts.

I also worked on integrating this method with a full height layout, so the footer remains at the bottom of the view port if the page isn't long enough. The result is fairly stable, except for Opera... still need some work, it's getting very close to a full-featured and flexible layout, only using CSS.

References

A List Apart: Faux Columns
http://alistapart.com/articles/fauxcolumns/
A List Apart: In Search of the Holy Grail
http://www.alistapart.com/articles/holygrail
A List Apart: Creating Liquid Layouts with Negative Margins
http://alistapart.com/articles/negativemargins
Ingo Chao: Companion column method
http://www.satzansatz.de/cssd/companions.html
CSS layout: 100% height with header and footer
http://www.xs4all.nl/~peterned/examples/csslayout1.html
How to Make Equal Columns in CSS
http://www.search-this.com/2007/02/26/how-to-make-equal-columns-in-css/
Position is Everything: In search of the One True Layout
http://www.positioniseverything.net/articles/onetruelayout/
Add a comment 10 comments

This is not wordpress, it's

This is not wordpress, it's Drupal, and yes, I did it myself :)

Very nicely done. Now, how

Very nicely done.

Now, how do I add border to these, say 2-column, layout with margin to separate them?

What about using css on the

What about using css on the fake columns ?
You can style the columns using css the same way you can style any element of the page.

something like this :

#bgleft {
    border-right:1px solid #ccc;
}

Makes sense ?

Fabulous!!! In the .css, is a

Fabulous!!! In the .css, is a .center definition needed for this markup: ?

You're right, it's not. It

You're right, it's not. It just inherited from my coding habits. But in this case, you don't need it.

A very neat method... and a

A very neat method... and a lovely Drupal theme too! Cheers!

Incidentally, the absolutely positioned element for each column can be nested inside its column so long as the column is positioned and the absolutely positioned element has no left position value. Keeps the HTML code tidy.

This method works great. I

This method works great. I rarely print, but I noticed when I print an example page from this site and my own equal-column-height pages, the formatting and .css are ignored. Is this just an error in my .css, or has anyone else experienced this, too?

My bad, I didn't really paid

My bad, I didn't really paid attention to the print.css
I'll try to find some time to work on this

Wow, thanks for the speedy

Wow, thanks for the speedy reply. Sounds great. In the meantime, I'll work on a print.css that uses conventional columns and see how that goes. The screen versions are really ingenious, though.

Very good job, guy. I have a

Very good job, guy. I have a problem that I supose it has to be with the header and footer problem with headen columns, so is the links in footer doesn't work.

Any suggesiont?

Thanks!

Add a comment