The long-lost multi-column layout

Posted by Raoul Snyman on March 28, 2006 on 11:42 pm | In (X)HTML, CSS, Design |

Ok, it’s not “long-lost” but I had to think up a nice title, ok? And besides, it’s more in reference to the method of doing the multi-column layout. Although that’s not “long-lost” either…

Ever since I saw a guy do a presentation on usability of web sites, I’ve wanted to see a layout that was correct in it’s coding, took minimal hacks of code, and used as little code as possible (i.e. no unecessary DIVs). A few weeks back I found an article on A List Apart just like this. I immediately implemented it in the template for www.websitewriters.co.za.

So, you have a web site with a fixed width left-hand column, a fixed width right-hand column, and a fluid centre column which must adapt to the size of the screen.

In my old templates, my basic code used to look like this:

<div id="header"></div>
 
<div id="container">
  <div id="left"></div>
  <div id="right"></div>
  <div id="centre"></div>
</div>
 
<div id="footer"></div>

This code looks ok, it’s simple and clean, no uncessary DIVs, so what’s the problem?

Well, in terms of usability, especially for blind people, this isn’t good. The person is going to have to read through both your columns (which they’re probably not *that* interested in) before they get to the content (which is what they’re actually after). It doesn’t matter that your right-hand news column appears on the right-hand side on your site, when you disable the styles in Firefox, you’ll see that it appears above the content. Disable the styles in Firefox for all your designs, and have a look at what happens to them. It’s a very interesting exercise.

Your code should rather look like this:

<div id="header"></div>
 
<div id="container">
  <div id="centre" class="column"></div>
  <div id="left" class="column"></div>
  <div id="right" class="column"></div>
</div>
 
<div id="footer"></div>

Ok, that’s grand, BUT… how do you get it right in CSS? That was my main problem when I was looking to change my sites to this better document structure. How did I get my CSS to make my columns appear on the right and the left of the content, even though in the code they’re below the content? Some CSS magic, of course.

The way it works is pretty simple actually (must be, even *I* got it right). We use padding and negative margins to get the columns to line up nicely.

Firstly, we create the container DIV and set it’s right and left padding equal to the respective columns’ widths.

<div id="header"></div>
 
<div id="container"></div>
 
<div id="footer"></div>

#container
{
  padding-left: 100px;   /* left width */
  padding-right: 100px;  /* right width */
}

container1.jpg
Figure 1.

Then we our 3 columns (the left, right and fluid middle column). We set their widths, and then float them all to get them in line. We must also just set the footer to clear all so that it stays beneath all the columns.

<div id="header"></div>
 
<div id="container">
  <div id="centre" class="column"></div>
  <div id="left" class="column"></div>
  <div id="right" class="column"></div>
</div>
 
<div id="footer"></div>

#container .column {
  float: left;
}
#centre {
  width: 100%;
}
#left {
  width: 100px;  /* left width */
}
#right {
  width: 100px;  /* right width */
}
#footer {
  clear: both;
}

Do note that the 100% width of the centre column is referring to the width of the containing DIV without the padding. We’ll see the 100% width later on again, but remember that it refers to the inside width of the container DIV.

But if you look at the layout now as it stands, you’ll see that the columns are not lined up. In fact, the left and right columns are underneath the centre column, as illustrated below. This is because the width of the centre column is set to 100%, so it’s taking up all the space, and thus the left and right columns wrap underneath it.

centre.jpg
Figure 2.

So let’s now pull the left hand column into place. Firstly, what we need to do is to pull the left column across using negative margins. However, that makes the left column overlap the centre column, but it’s still within the inside of the container DIV (see figure 3). The right column is now up against the left inner side of the container DIV and still sitting underneath the centre column.

left1.jpg
Figure 3.

#left {
  width: 100px;        /* left width */
  margin-left: -100%;
}

So what we now do is to set the positioning of the columns to relative, and the right edge of the left column to its width, which pushes it away from the left edge of the inner bounds of the container DIV, and the left edge of the centre column (see figure 4).

left2.jpg
Figure 4.

And here’s the code:

#container .columns {
  float: left;
  position: relative;
}
#left {
  width: 100px;        /* left width */
  margin-left: -100%;
  right: 100px;        /* left width */
}

The last thing we want to do now is to set the right column in place. This, once again, is achieved through negative margins, which pulls the column into the container DIV’s padding on the right.

#right {
  width: 100px;          /* right width */
  margin-right: -100px;  /* right width */
}

So now both our columns are in the right place, and the columns are all flush with the footer at the bottom too, as seen below.

right.jpg
Figure 5.

Well, the last things we need to do is to make sure it works properly when the browser window is resized, and then to make sure this works in all browsers.

When resizing a standards compliant browser, the centre column can become smaller than the column, and breaks the layout. So we need to set the min-width of the body tag. IE 6 doesn’t support the mind-width property, but then it also doesn’t suffer from the problem described above.

body {
  min-width: 300px;  /* 2x left width + right width */
}

Of course, IE being IE, we need a few hacks to make sure our layout works in it too. The negative margins of the left column pull it too far, so we need to use the * html hack to set the left property of the left column to the same width as the right hand column (another one of IE’s “features”), and hide it from standards compliant browsers.

* html #left {
  left: 100px;  /* right width */
}

Well, that’s all I have to say about this. There are a few improvements that can still be done (like removing the container DIV), but I’ll leave that up to you to figure out. And lastly, here is the original A List Apart article by Matthew Levine that I based this on.

And here’s the full CSS:

body {
  min-width: 300px;      /* 2x left width + right width */
}
#container {
  padding-left: 100px;   /* left width */
  padding-right: 100px;  /* right width */
}
#container .column {
  position: relative;
  float: left;
}
#centre {
  width: 100%;
}
#left {
  width: 100px;          /* left width */
  right: 100px;          /* left width */
  margin-left: -100%;
}
#right {
  width: 100px;          /* right width */
  margin-right: -100px;  /* right width */
}
#footer {
  clear: both;
}
/*** IE6 Fix ***/
* html #left {
  left: 100px;           /* right width */
}

1 Comment »

RSS feed for comments on this post. TrackBack URI

  1. How would you do it if you have the following :

    ... /* 40 - 400 lines of text */

    and want the pageheader fixed on top with the pagefooter fixed at the bottom and the pagecontents scrolling (not going under/over the page header/footer ?

    Comment by rudied — August 25, 2006 #

Leave a comment

You must be logged in to post a comment.

Powered by WordPress with websitewriters.co.za theme, design by Saturn Laboratories.
Entries and comments feeds. Valid XHTML and CSS. ^Top^