@ Loup's Impossible? Like that would stop me.

(update July 2022: This tutorial is obsolete. Now we tend to use flexbox or grids.)

My ultimate CSS layout

The goal is to have a 3-columns, liquid layout with the cleanest possible html code. By clean, I mean something like this:

<!doctytpe html>
<html>
  <head><link rel="stylesheet" href="example.css" /></head>
  <body>
    <header>  header  header  header  header  header  </header>
    <article> article article article article article </article>
    <nav>     nav     nav     nav     nav     nav     </nav>
    <aside>   aside   aside   aside   aside   aside   </aside>
    <footer>  footer  footer  footer  footer  footer  </footer>
  </body>
</html>

Header first, then the main content. Side columns come last. This is better for text browsers, search engines, and Über Geeks who disable CSS. Note that I use html5 tags avoid clutter. The actual examples use <div> tags.

Default layout

First, the colors. They help visualizing the layout. If you are using Firefox, you should also try the firebug extension. It helps visualizing even the margins of the boxes.

/* html5 reset */
article, nav, aside, header, footer { display:block;
                                      padding:1em; }
/* colors */
html           { background-color:#fff; }
body           { background-color:#ddd; }
header, footer { background-color:#aaa; }
nav, aside     { background-color:#8aa; }
article        { background-color:#a8a; }

The result is here.

Fixed width layout

The total width is specified in ems. Don’t use pixel widths, they don’t scale properly. The trick here is negative margins. <article> comes first and is 30ems wide (this count it’s “width” plus the padding and left margin. <nav> should fit on the right, but a negative margin of 30ems push it on the left. This leaves enough room for <aside>, which fits on the right.

body    { width:35em; margin:auto;                   }
article { float:left; margin-left:5em;   width:23em; }
nav     { float:left; margin-left:-30em; width: 3em; }
aside   { float:left; margin-left:0;     width: 3em; }
footer  { clear:both; }

The result is here.

Liquid layout with percentages

The technique is exactly the same. Just replace all em mesures by percentages.

article, nav, aside, header, footer { padding:4% }
body    { width:50%; margin:auto;                  }
article { float:left; margin-left:18%;  width:56%; }
nav     { float:left; margin-left:-82%; width:10%; }
aside   { float:left; margin-left:0;    width:10%; }
footer  { clear:both; }

The result is here (you may see a rounding error resulting in an 1-off pixel). See what happens when you resize your browser.

Ultimate: liquid layout with fixed side columns

Percentages are not ideal. Side columns generally have few text, and should vary with the font size only. We need <article> to be as wide as <body>, minus the width of the side columns. We can achieve this by not specifying the width of <article>. It will then expand as much as it can, minus the specified margins.

body    { width:50%; margin:auto;                         }
article { float:left; margin-left:  5em; margin-right:5em }
nav     { float:left; margin-left:-35em; width: 3em;      }
aside   { float:left; margin-left: -5em; width: 3em;      }
footer  { clear:both; }

The result is here. Do we have found the Holy Grail?

Compromise

No. When <article> doesn’t have enough content, it narrows and wrecks havoc in the layout. The resulting catastrophy is here.

I found 2 ways to compensate. The first is to artificially add content to <article>, with some additionnal CSS:

article:after{ content:"m m m m m m m m m m m m m m m m m m m";}

The result is here. Don’t forget to change the font color, so it matches the background:

article:after{ color:#a8a; }

The result is here. The letters will disapear, but the gap will remain.

The second way is to pollute the html code a bit: wrap <article> in a <div id=wrap> tag:

<!doctytpe html>
<html>
  <head><link rel="stylesheet" href="example.css" /></head>
  <body>
    <header>  header  header  header  header  header  </header>
    <div id=wrap>
      <article> article article article article article </article>
    </div>
    <nav>     nav     nav     nav     nav     nav     </nav>
    <aside>   aside   aside   aside   aside   aside   </aside>
    <footer>  footer  footer  footer  footer  footer  </footer>
  </body>
</html>

And the CSS:

body    { width:50%; margin:auto;                         }
#wrap   { float:left; width:100%; padding:0; margin:0;    }
article {             margin-left: 5em ; margin-right:5em }
nav     { float:left; margin-left:-100%; width: 3em;      }
aside   { float:left; margin-left:-5em ; width: 3em;      }
footer  { clear:both; }

The result is here. Note that it works well with little content. Because <article> is not a float any more, it will extend to its maximum width no matter what.

How to choose

If you want absolutely no ugliness, you will have to choose a percentage based layout, or an em based one (pixel based sizes are evil and ugly, period). If you must have a liquid layout, you will have to choose where to put the ugliness: in the stylesheet, or in the html code. And don’t forget that even liquid layouts have limits. If you let it be too wide, long lines will be hard to read. If you want to support very narrow screens, you should write an alternate style sheet with only one column.