Title:       Relatively Simple 3 equal-height columns CSS liquid Layout
Author:      Gladstone
Email:       gladstone@vene.ws
Member ID:   1477791
Language:    HTML, CSS
Platform:    Any OS, IE 6/7, Firefox 2, Mozilla 1.7, Opera 9.1, Safari 1.3.2, NN 8.1.3, NN9
Technology:  Web, HTML, CSS, Relativeness, Overflow
Level:       Advanced
Description: This article tries to explain a new approach to the annoying issue of obtaining a three (or even more) equal-height columns liquid layout with the usage of CSS and (X)HTML only. My own solution avoids faux-columnS and super-padding tricks (and so problems caused by those methods).
Section      Web Design
SubSection   Layouts, CSS

Equal height 3 columns CSS Liquid Layout

Index

Live Demo

Introduction


Preface

All web developers know it, it’s one of the most annoying problems when facing to the creation of (X)HTML CSS-based layouts: the 3 equal-height columns layout. The best solution so far was (or it’s still if you’re going to dislike my own solution) the faux-column method, which uses background images to simulate columns. The problem is that I’m working at a large project which should be the more flexible than it could and the faux-column method isn't the best example of flexibility.
My solution tries to satisfy flexibility needs allowing the usage of 2 up to 3, 4 or even more equal-height columns with background colors specified only through background-color CSS property.

Note: I had to change some article styles to have it working with the codeproject.com website, because the latter is not XHTML compliant, but I left code in the examples as it should be for XHTML pages, because this solution is thought to work only with XHTML and I don't support HTML requests (like "this doesn't work in my HTML 3.0 website" etc.).


Advantages and Disadvantages

Like every other solution, mine also has advantages and disadvantages. As always it's all about what you get and what you loose in getting it.

Advantages:

Disadvantages:

The Method


Relative and overflow

Having three vertical columns with the center one elastic is very trivial in HTML. It's all about putting 3 divs near each other and floating them. To make those columns appear of the same height, however, we have to make their backgrounds appear of the same height. A key feature of HTML language is that each container (mainly each element) has a default transparent background thus making it possible to have a (theorically) infinite amount of overlapping layers with the latter having the same background as the first one (if no subsequent background-color is set).

So the problem of having three equal-height columns just comes down in obtaining, in some way, a view separated in 3 stripes of the same height upon which we put the 3 divs which actually contain the columns.
When thinking about a way to obtain this 3-stripes-view, I started pointing my mind at what I was in need of first: that is, a way to make some html elements to have the same height whatever is the higher between them. As we know, this is possible by using block-level elements each inside the other. So, what we all need, is to put divs each inside one other and move them in some way to obtain our three stripes view, upon which we can put, as I said, our three real (that is, physical) columns. This is just possible using CSS properties position: relative (which lets us shift the child divs) and overflow: hidden (which lets us hide those portions of child divs which otherwise would overflow the parent space).
Let's see how the all thing works:

Here we have some examples which explain step by step and in details how key concepts work. Each example includes 2 divs, one with a blue-like background (div.parent-box) and the other with a yellow-like background (div.child-box). Those divs represent what we're going to do later to create page-wide columns. The blue div is the container box while the yellow one is the contained box. Near the example box there's a table which shows CSS properties set for the elments respectively. I put in there only the most important and removed those added only to make things appear more clear (like the borders).

The first one is an empty example. That is, the two simple parent and child divs:

e
x
a
m
p
l
e

1
Mark-up
<div class="parent-box">
    <div class="child-box">
    </div>
</div>
Parent Styles Child Styles
  • width: 250px;
  • background: #00CCCC;
  • background: #FFFFCC;

Here the divs are just one inside another so we can see the child one only, because it fills all the parent space.

The second example introduces the concept of relativeness:

e
x
a
m
p
l
e

2
Mark-up
<div class="parent-box">
    <div class="child-box">
    </div>
</div>
Parent Styles Child Styles
  • width: 250px;
  • background: #00CCCC;
  • background: #FFFFCC;
  • position: relative;
  • left: 40px;
  • margin: 10px 0;

Here the child div is shifted a bit away from the left. I put top and bottom margins in the child box to highlight the change.

The following example instead shows what happens when the overflow property of the parent is set to overflow: hidden. As you can see, the child box is cut off where the parent one outlines end:

e
x
a
m
p
l
e

3
Mark-up
<div class="parent-box">
    <div class="child-box">
    </div>
</div>
Parent Styles Child Styles
  • width: 250px;
  • background: #00CCCC;
  • position: relative;
  • overflow: hidden;
  • background: #FFFFCC;
  • position: relative;
  • left: 40px;
  • margin: 10px 0;

Here the child div is shifted a bit away from the left as before. I removed margins and added a right-padding to the current paragraph of text to make the text more readable.


More relative and overflow

Now that we've seen how the base concepts work, let's make it all a bit more complicated, using 3 divs (those that will be our page-wide columns at the end).

As seen before we can create a stripe (that is, a column background) simply by setting the parent background color to the color we want for that stripe and then shifting the child box of an amount equal to the width we want for the stripe/column.
When adding 3 stripes though, when we shift the first child, the second child will obviously shift too (we can call this second child the grandson, being the child of the child of the parent). Since we have to shift the grandson from the right (to create a right stripe) we need to make the grandson left margin overlap the parent right margin (should we call it the grandfather?). In such a way we'll be able to put a relative shift from the right equal to the width of the right column we want.
The best way to make those margins overlap, is to reset the position of the child, that is to make the left margins overlap and then add a margin-left of 100%. We're going to do this using an additional container between the child and the grandson, applying those styles to this new container, which will be called reset-box. After this we'll have the grandson left margin overlaps the grandfather right margin. Now all we need is to right-shift the grandson of the amount we want the right column width of.
The last thing to do is to adjust the content position. In fact all the contents now lay where the grandson box do. Simply applying the same method as before, we add an additional container between the grandson and the contents, calling it content-box. Then we relatively left-shift it of the amount of the right column and we set its left-margin to -100% (note the minus), thus making its left margin to overlap the left margin of the original parent (the grandfather).

The following example shows the result of the above speculation. The width chosen for the left column is 40px while the right columns width is 25%. Look at the mark-up and new styles very carefully to understand well where the above width values go and how does the all thing work:

e
x
a
m
p
l
e

4
Mark-up
<div class="parent-box">
  <div class="child-box">
    <div class="reset-box">
    <div class="grandson-box clearfix heightfix">
      <div class="content-box">
      </div>
    </div>
    </div>
  </div>
</div>
Parent Styles Child Styles
  • width: 250px;
  • background: #00CCCC;
  • position: relative;
  • overflow: hidden;
  • background: #FFFFCC;
  • position: relative;
  • left: 40px;
  • width: 100%;
Reset Styles Grandson Styles
  • position: relative;
  • width: 100%;
  • left: -40px;
  • margin-left: 100%;
  • background: transparent;
  • position: relative;
  • width: 100%;
  • left: -25%;
  • background: #D0EEC0;
Content Styles
  • position: relative;
  • width: 100%;
  • left: 25%;
  • margin-left: -100%;
  • background: transparent;

As you can see, now we have the 3 stripes view we were trying to obtain. The mark-up is a lot more tricky than in previous examples.
In fact we use 5 divs instead of 2 as usual, so we have 3 extra divs; also having 3 stripes requieres the usage of two fixes, the clearfix and the heightfix.

Also, the code will get more tricky when we'll be adding border to the columns. I'll get through this later, in a paragraph below.

The following example shows the same example as above (Example 4) but with the parent blue-like box CSS property overflow set to overflow: visible thus making the contained boxes fully visible. Also, I put in some margins to make things more clear.

e
x
a
m
p
l
e

4
.
1

This is the same example as above but with overflow: visible set for the parent box (blue-like one) and with some margins to see how and where al the containers go.
Have a look at the mark-up and styles in the example 4 above to understand how the all thing works.

The following example shows the same example as above (Example 4) but with the parent blue-like box width set to a higher value: width: 400px. Note that changing the width of the layout required only the change of a single CSS value for the main container. Note also that because we chose a percentage fixed width of 25% for the right column, this also changed its size accordingly.

e
x
a
m
p
l
e

4
.
2

This is the same as the example 4 but with the width of the main container increased to 400px.
This simple change not only made the entire layout wider without malfunctions or problems, but also made the right column (which width was set to 25%) change its width accordingly, while the center filled the remaining space. This is what I mean for flexibility.


Let's put two cols

Now that we've looked at how the key concepts work, let's make a first example with two columns. It will have about the same structure of first three two-stripes examples, but in addition its contents will be floated to create the physical structure of the two columns.

From now on we're going to change names (and so CSS classes) through which we'll be referring to container divs in the future. The reason for this change is that from now on we'll be talking about columns (also physical ones) so stripe divs (those divs we use to create columns backgrounds) will be called as the column they're the background of, apart from the main container (the one which contains everything else), which will be called, strangely enough, main-box.

The following example shows a two columns example. Note that as always, for clarity, I didn't put any border style in the CSS code table cell although the main-box container div got a dark-red solid one:

e
x
a
m
p
l
e

5
Mark-up
<div class="main-box">
  <div class="right-box">
    <div class="content-box clearfix heightfix">
      <div class="left">
      </div>
      <div class="right">
      </div>
    </div>
  </div>
</div>
main-box Styles right-box Styles
  • position: relative;
  • width: 250px;
  • background: #00CCCC;
  • overflow: hidden;
  • position: relative;
  • width: 100%;
  • background: #FFFFCC;
  • left: 25%;
content-box Styles left Styles
  • position: relative;
  • width: 100%;
  • left: -25%;
  • background: transparent;
  • width: 25%;
  • float: left;
  • background: transparent;
right Styles ie right Styles
  • margin-left: 25%;
  • background: transparent;
  • height: 1%;
  • margin: 0;
ie left Styles
  • margin-right: -3px;
This is the left col. It wraps well on stripe margin.
I did not put padding, margins or any type of layout logic into the columns text. Although this make the columns appear ugly, it also shows how the things work and how the stripe margins are respected by the physical columns.
As you can see text wraps exactly where the stripe (that is, the column background) ends, thus it makes the stripe appear as being the real column.
IE 3px gap Hacks

As you can see in the code table above, there are two cells more than usual in the last two rows, which headers are respectively IE right Styles and IE left Styles. It means that those styles work only for Internet Explorer (version 6 or lower) and are applied using the special * html selector.
This is the CSS code which actually gets the job done:

	* html div.two-cols div.right {
	height: 1%;
	margin: 0;
	}
	
	* html div.two-cols div.left {
	margin-right:-3px;
	}

Those hacks are meant to remove the 3px space between the left and the right column.
In the future, when we'll be working on 3 columns layouts, the right styles will be applied to center column, and both left and right columns will have a negative margin to avoid the gap.


Border is there

As I mentioned above, all the thing get a bit more tricky when border comes. Although there are no changes when adding external borders, in fact you simply have to set respective borders in main-box container (border-left for the left border of the left column, top-border for the top border and so on) problems come out when you try to add borders between columns.
The reason is that when you put a border in a container, the border of the child of the container won't overlap the border of the parent, instead it will be put just next it. So, when relatively shifting our child divs, their position will be further moved by an amount equal to the previous border size.

The following example is about the same of Example 5 (I used the same textual contents too) but with a border added between the two columns. This is possible by setting the right-box container border-left CSS property. I put a large border (10px) to highlight the problem:

e
x
a
m
p
l
e

5
.
1
Mark-up
<div class="main-box">
  <div class="right-box">
    <div class="content-box clearfix heightfix">
      <div class="left">
      </div>
      <div class="right">
      </div>
    </div>
  </div>
</div>
main-box Styles right-box Styles
  • position: relative;
  • width: 250px;
  • background: #00CCCC;
  • overflow: hidden;
  • position: relative;
  • width: 100%;
  • background: #FFFFCC;
  • left: 25%;
  • border-style: solid;
  • border-color: #993333;
  • border-left-width: 10px;
content-box Styles left Styles
  • position: relative;
  • width: 100%;
  • left: -25%;
  • background: transparent;
  • width: 25%;
  • float: left;
  • background: transparent;
right Styles ie right Styles
  • margin-left: 25%;
  • background: transparent;
  • height: 1%;
  • margin: 0;
ie left Styles
  • margin-right: -3px;
This is the left col. It wraps well on stripe margin.
I did not put padding, margins or any type of layout logic into the columns text. Although this make the columns appear ugly, it also shows how the things work and how the stripe margins are respected by the physical columns.
As you can see text wraps exactly where the stripe (that is, the column background) ends, thus it makes the stripe appear as being the real column.

As you can see the layout is all moved to the right by the same size as the width of the border. So, the only thing we need to do, is to reset the final position of the whole layout from the right, of the same amount as the left border width said above (10px). In addition we need to put a padding-left of the same dimension in the right div to avoid the latter overlapping the border.

The following example is about the same of Example 5.1 but with the two changes mentioned above, to adjust the layout with the border:

e
x
a
m
p
l
e

5
.
2
Mark-up
<div class="main-box">
  <div class="right-box">
    <div class="content-box clearfix heightfix">
      <div class="left">
      </div>
      <div class="right">
      </div>
    </div>
  </div>
</div>
main-box Styles right-box Styles
  • position: relative;
  • width: 250px;
  • background: #00CCCC;
  • overflow: hidden;
  • position: relative;
  • width: 100%;
  • background: #FFFFCC;
  • left: 25%;
  • border-style: solid;
  • border-color: #993333;
  • border-left-width: 10px;
content-box Styles left Styles
  • position: relative;
  • width: 100%;
  • left: -25%;
  • background: transparent;
  • margin-left: -10px;
  • width: 25%;
  • float: left;
  • background: transparent;
right Styles ie right Styles
  • margin-left: 25%;
  • background: transparent;
  • padding-left: 10px;
  • height: 1%;
  • margin: 0;
ie left Styles
  • margin-right: -3px;
This is the left col. It wraps well on stripe margin.
I did not put padding, margins or any type of layout logic into the columns text. Although this make the columns appear ugly, it also shows how the things work and how the stripe margins are respected by the physical columns.
As you can see now the text wraps again exactly where the stripe (that is, the column background) ends, thus it makes the stripe appear as being the real column and the border as being a real column border.

The three of them

Now that all the key concepts were discussed, we can introduce our first complete example with the infamous three columns.

The following example shows our final 3 equal-height columns structure. As you can see from the mark-up code below, the right-box changed its name to center-box because it became the center of our layout because of the new green-like right column inserted. Apart from changing name, the CSS styles remained unchanged. Also note that in the example below (Example 6) the width settings are 25% for the left column and 40px for the right one, with the center column filling the remaining space:

e
x
a
m
p
l
e

6
Mark-up
<div class="main-box">
  <div class="center-box">
  <div class="reset-box">
  <div class="right-box">
    <div class="content-box clearfix heightfix">
      <div class="left">
      </div>
      <div class="right">
      </div>
      <div class="center">
      </div>
    </div>
  </div>
  </div>
  </div>
</div>
main-box Styles center-box Styles
  • position: relative;
  • width: 250px;
  • background: #00CCCC;
  • overflow: hidden;
  • position: relative;
  • width: 100%;
  • background: #FFFFCC;
  • left: 25%;
  • border-style: solid;
  • border-color: #993333;
  • border-left-width: 1px;
reset-box Styles right-box Styles
  • position: relative;
  • width: 100%;
  • left: 100%;
  • margin-left: -25%;
  • background: transparent;
  • position: relative;
  • width: 100%;
  • background: #D0EEC0;
  • left: -2px;
  • border-style: solid;
  • border-color: #993333;
  • border-left-width: 1px;
  • margin-left: -40px;
content-box Styles left Styles
  • position: relative;
  • width: 100%;
  • background: transparent;
  • left: 40px;
  • margin-left: -100%;
  • width: 25%;
  • float: left;
  • background: transparent;
right Styles center Styles
  • margin-left: 25%;
  • background: transparent;
  • padding-left: 10px;
  • width: 40px;
  • float: right;
  • margin-left: 25%;
  • margin-right: 40px;
  • padding-left: 1px;
  • padding-right: 1px;
  • background: transparent;
ie center Styles ie left Styles
  • height: 1%;
  • margin: 0;
  • margin-right: -3px;
ie right Styles
  • margin-left: -3px;
This is the left col. It wraps well on stripe margin.
r
i
g
h
t

c
o
l
u
m
n
I did not put padding, margins or any type of layout logic into the columns text. Although this make the columns appear ugly, it also shows how the things work and how the stripe margins are respected by the physical columns.
As you can see now the text wraps again exactly where the stripe (that is, the column background) ends, thus it makes the stripe appear as being the real column and the border as being a real column border.

The following is the same of Example 6, apart from the wider main-box container. I increased its width to show how the layout is flexible and can adapt itself to the space it is put in. I left the same textual contents within the columns to highlight the difference:

e
x
a
m
p
l
e

6
.
1
This is the left col. It wraps well on stripe margin.
r
i
g
h
t

c
o
l
u
m
n
I did not put padding, margins or any type of layout logic into the columns text. Although this make the columns appear ugly, it also shows how the things work and how the stripe margins are respected by the physical columns.
As you can see now the text wraps again exactly where the stripe (that is, the column background) ends, thus it makes the stripe appear as being the real column and the border as being a real column border.

As you can see, being icreased the width of the whole layout, the left column width also increased accordingly because it was set to 25%; instead, the right column width remained untouched because it was pixel-fixed at 40px. Also, as you can easily see, the center column (which is elastic) filled the remaining space and because of the more horizontal space available, its height decreased thus no more being the highest column. In fact now the highest column is the right one, and as you can see, all the backgrounds are of the same height.

The code


The markup

I already mentioned in the disadvantages sections, that the markup contains 3-4 divs above the norm (the exact number depends on your usual layout style) and this can be unacceptable by some people. As an extenuation I can say that the number of divs can be (probabily) reduced working around borders and containers needed to reset the positions (also because of borders). Anyway those 3 extra divs are not a big problem to me, for this reason I've not worked a lot to find a way to reduce their quantity.
This is the (X)HTML markup:

<div class="main-box">
  <div class="center-box">
  <div class="reset-box">
  <div class="right-box">
    <div class="content-box clearfix">
      <div class="left">
      </div>
      <div class="right">
      </div>
      <div class="center heightfix">
      </div>
    </div>
  </div>
  </div>
  </div>
</div>

The style

Below there's the clean and ready-to-use CSS code for a working layout. Although the code can seem tricky, after a careful reading and if you understood the method used (explained in section 2 - The Method) I think it will be trivial to realize what you need to change to have your own layout. That is for example to incrase the width of columns or change the background color and such.
So, this is the CSS code:

div.main-box {
position: relative;
width: 500px;
overflow: hidden;
background: #D0E1E1;
border: solid 1px #993333;
}
div.center-box {
position: relative;
width: 100%;
left: 25%;
background: #FFFFCC;
border-left: solid 1px #993333;
}
div.reset-box {
position: relative;
width: 100%;
left: 100%;
margin-left: -25%;
}
div.right-box {
position: relative;
width: 100%;
margin-left: -40px;
background: #D0EEC0;
border-left: solid 1px #993333;
left: -2px;
}
div.content-box {
position: relative;
width: 100%;
margin-left: -100%;
left: 40px;
}
div.left {
float:left;
width:25%;
}
div.right {
float: right;
width: 40px;
text-align: center;
text-transform: uppercase;
}
div.center {
margin-left: 25%;
margin-right: 40px;
padding-left: 1px;
padding-right: 1px;
}
* html div.center {
height:1%;
margin:0;
}
* html div.left {
margin-right:-3px;
}
* html div.right {
margin-left:-3px;
}
.clearfix:after {
content: "."; 
display: block;
height: 0px;
clear: both; 
visibility: hidden;
}		
.heightfix:before {
content: '.';
display: block;
visibility: hidden;
height: 0;
}

Examples


Three columns empty

The next one is a complete example with three columns plus an header and a footer. There are no contents in there, just some <br⁄> to make the layout grow in height. Widths here are 25% for the left column and 120px for the right one, while the whole layout width is 80%.

XHTML Mark-up
<div class="main-box">
  <div class="top-box">
    <br/>top content<br/><br/>
  </div>
  <div class="center-box">
  <div class="reset-box">
  <div class="right-box">
    <div class="content-box clearfix">
      <div class="left">
        <p>l<br/>e<br/>f<br/>t<br/><br/>c<br/>o<br/>l<br/>u<br/>m<br/>n</p>
      </div>
      <div class="right">
        <p>r<br/>i<br/>g<br/>h<br/>t<br/><br/>c<br/>o<br/>l<br/>u<br/>m<br/>n</p>
      </div>
      <div class="center heightfix">
        <p>c<br/>e<br/>n<br/>t<br/>e<br/>r<br/><br/>c<br/>o<br/>n<br/>t<br/>e<br/>n<br/>t</p>
      </div>
    </div>
  </div>
  </div>
  </div>
  <div class="footer-box">
    <br/>footer content<br/><br/>
  </div>
</div>
CSS Code
div.main-box {
position:relative;
width:80%;
margin:0 auto;
overflow:hidden;
background:#D0E1E1;
border:solid 1px #993333;
}
div.top-box {
clear:both;
background:#336666;
text-align:center;
text-transform:uppercase;
border-bottom:solid 1px #993333;
}
div.footer-box {
clear:both;
background:#336699;
text-align:center;
text-transform:uppercase;
border-top:solid 1px #993333;
}
div.center-box {
position:relative;
width:100%;
left:25%;
background:#FFFFCC;
border-left:solid 1px #993333;
}
div.reset-box {
position:relative;
width:100%;
left:100%;
margin-left:-25%;
}
div.right-box {
position:relative;
width:100%;
margin-left:-120px;
background:#D0EEC0;
border-left:solid 1px #993333;
left:-2px;
}
div.content-box {
position:relative;
width:100%;
margin-left:-100%;
left:120px;
}
div.left {
float:left;
width:25%;
text-align:center;
text-transform:uppercase;
}
div.right {
float:right;
width:120px;
text-align:center;
text-transform:uppercase;
}
div.center {
margin-left:25%;
margin-right:120px;
padding-left:1px;
padding-right:1px;
text-align:center;
text-transform:uppercase;
}
* html div.center {
height:1%;
margin:0;
}
* html div.left {
margin-right:-3px;
}
* html div.right {
margin-left:-3px;
}
.clearfix:after {
content: "."; 
display: block;
height: 0px;
clear: both; 
visibility: hidden;
}		
.heightfix:before {
content:'.';
display:block;
visibility:hidden;
height:0;
}

Three columns and content

See next example to have more details/information.

XHTML Mark-up
<div class="main-box">
  <div class="top-box">
    top;
  </div>
  <div class="center-box">
  <div class="reset-box"> 
  <div class="right-box">
    <div class="content-box clearfix">
      <div class="left-col">
        left;
      </div>
      <div class="right-col">
        right;
      </div>
      <div class="center-col heightfix">
        center;
      </div>
    </div>
  </div>
  </div> 
  </div>
  <div class="bottom-box">
    bottom;
  </div>
</div>
CSS Code
div.main-box {
position:relative;
text-align:left;
overflow:hidden;
width:80%;
background:#006699;
}
div.top-box {
background:#0099CC;
}
div.bottom-box {
background:#6699CC;
}
div.center-box {
position:relative;
width:100%;
left:120px;
background:#0066CC;
}
div.reset-box {
position:relative;
width:100%;
left:100%;
margin-left:-120px;
} 
div.right-box {
position:relative;
width:100%;
margin-left:-22%;
background:#99CCCC;
}
div.content-box {
position:relative;
width:100%;
margin-left:-100%;
left:22%;
}
div.left-col {
float:left;
width:120px;
}
div.right-col {
float:right;
width:22%;
}
div.center-col {
margin-left:120px;
margin-right:22%;
}
* html div.center-col {
height:1%;
margin:0;
}
* html div.left-col {
margin-right:-3px;
}
* html div.right-col {
margin-left:-3px;
}
.clearfix:after {
content: "."; 
display: block;
height: 0px;
clear: both; 
visibility: hidden;
}
.heightfix:before {
content:'.';
display:block;
visibility:hidden;
height:0;
}

Three columns, content and border

The following is a real-world hypothetical sample layout. I added contents and styles to make it look as a general (ugly?) website would look like. In the next code table I removed real contents and replaced them with placeholders to save space, see at the working example source code if you want to look at the contents too. Also, I removed from the style code all those styles that are not related directly to the three columns layout needs. All the CSS code you'll see in the next table is contained in a ready-to-use CSS file named threecol.css which you can retrive from the links at the bottom of the table itself. This file, as I said, is ready to be used in your own pages and contains also detailed descriptions (in CSS comments) which exaplain what values are meant for what purpose (again), so that you can easily change them to have your own custom layout.

XHTML Mark-up
<div class="main-box">
  <div class="top-box">
    top;
  </div>
  <div class="center-box">
  <div class="reset-box"> 
  <div class="right-box">
    <div class="content-box clearfix">
      <div class="left-col">
        left;
      </div>
      <div class="right-col">
        right;
      </div>
      <div class="center-col heightfix">
        center;
      </div>
    </div>
  </div>
  </div> 
  </div>
  <div class="bottom-box">
    bottom;
  </div>
</div>
CSS Code
div.main-box {
position:relative;
text-align:left;
overflow:hidden;
width:80%;
background:#006699;
border:solid 10px white;
}
div.top-box {
background:#0099CC;
border-bottom:solid 10px white;
}
div.bottom-box {
background:#6699CC;
border-top:solid 10px white;
}
div.center-box {
position:relative;
width:100%;
left:120px;
background:#0066CC;
border-left:solid 10px white;
}
div.reset-box {
position:relative;
width:100%;
left:100%;
margin-left:-120px;
} 
div.right-box {
position:relative;
width:100%;
margin-left:-22%;
left:-20px;
background:#99CCCC;
border-left:solid 10px white;
}
div.content-box {
position:relative;
width:100%;
margin-left:-100%;
left:22%;
}
div.left-col {
float:left;
width:120px;
}
div.right-col {
float:right;
width:22%;
}
div.center-col {
margin-left:120px;
margin-right:22%;
padding-left:10px;
padding-right:10px;
}
* html div.center-col {
height:1%;
margin:0;
}
* html div.left-col {
margin-right:-3px;
}
* html div.right-col {
margin-left:-3px;
}
.clearfix:after {
content: "."; 
display: block;
height: 0px;
clear: both; 
visibility: hidden;
}
.heightfix:before {
content:'.';
display:block;
visibility:hidden;
height:0;
}

Four columns

In the following example I'll try to use my method to create a layout with 4 columns. Although probabily not so useful (at least not like the 3 cols one) this layout can be handy to learn better how the whole method works.

XHTML Mark-up
<div class="main-box">
  <div class="top-box">
    <br/>top content<br/><br/>
  </div>
  <div class="left-box">
  <div class="center-box">
  <div class="reset-left-box">
  <div class="reset-box">
  <div class="right-box">
    <div class="content-box clearfix">
      <div class="left">
        <p>l<br/>e<br/>f<br/>t<br/><br/>c<br/>o<br/>l<br/>u<br/>m<br/>n</p>
      </div>
      <div class="more-left">
        <p>m<br/>o<br/>r<br/>e<br/><br/>l<br/>e<br/>f<br/>t<br/><br/>c<br/>o<br/>l<br/>u<br/>m<br/>n</p>
      </div>
      <div class="right">
        <p>r<br/>i<br/>g<br/>h<br/>t<br/><br/>c<br/>o<br/>l<br/>u<br/>m<br/>n</p>
      </div>
      <div class="center heightfix">
        <div class="center-no-left">
          <p>c<br/>e<br/>n<br/>t<br/>e<br/>r<br/><br/>c<br/>o<br/>n<br/>t<br/>e<br/>n<br/>t</p>
        </div>
      </div>
    </div>
  </div>
  </div>
  </div>
  </div>
  </div>
  <div class="bottom-box">
    <br/>bottom content<br/><br/>
  </div>
</div>
CSS Code
div.main-box {
position:relative;
width:80%;
margin:0 auto;
overflow:hidden;
background:#D0E1E1;
border:solid 10px #993333;
}
div.top-box {
background:#336666;
text-align:center;
text-transform:uppercase;
border-bottom:solid 10px #993333;
}
div.bottom-box {
background:#336699;
text-align:center;
text-transform:uppercase;
border-top:solid 10px #993333;
}
div.left-box {
position:relative;
width:100%;
left:25%;
background:#FFF0C0;
border-left:solid 10px #993333;
}
div.center-box {
position:relative;
width:100%;
left:100px;
background:#FFFFCC;
border-left:solid 10px #993333;
}
div.reset-left-box {
position:relative;
width:100%;
left:100%;
margin-left:-25%;
}
div.reset-box {
position:relative;
width:100%;
margin-left:-100px;
}
div.right-box {
position:relative;
width:100%;
margin-left:-120px;
background:#D0EEC0;
border-left:solid 10px #993333;
left:-30px;
}
div.content-box {
position:relative;
width:100%;
margin-left:-100%;
left:120px;
}
div.left {
float:left;
width:25%;
text-transform:uppercase;
}
div.more-left {
float:left;
width:100px;
margin-left:10px;
text-transform:uppercase;
}
div.right {
float:right;
width:120px;
text-transform:uppercase;
}
div.center-no-left {
margin-left:100px;
padding-left:10px;
}
div.center {
margin-left:25%;
margin-right:120px;
padding-left:10px;
padding-right:10px;
text-transform:uppercase;
}
* html div.center-no-left {
height:1%;
margin:0;
}
* html div.more-left {
margin-right:-3px;
}
* html div.right {
margin-left:-3px;
}
.clearfix:after {
content: "."; 
display: block;
height: 0px;
clear: both; 
visibility: hidden;
}		
.heightfix:before {
content:'.';
display:block;
visibility:hidden;
height:0;
}

Five columns?

This last example is for teaching purposes only. I don't think someone would ever need such a thing.

XHTML Mark-up
<div class="main-box">
  <div class="top-box">
    <br/>top content<br/><br/>
  </div>
  <div class="left-box">
  <div class="center-box">
  <div class="reset-left-box">
  <div class="reset-box">
  <div class="reset-right-box"
  <div class="more-right-box">
  <div class="right-box">
    <div class="content-box clearfix">
      <div class="left">
        <p>l<br/>e<br/>f<br/>t<br/><br/>c<br/>o<br/>l<br/>u<br/>m<br/>n</p>
      </div>
      <div class="more-left">
        <p>m<br/>o<br/>r<br/>e<br/><br/>l<br/>e<br/>f<br/>t<br/><br/>c<br/>o<br/>l<br/>u<br/>m<br/>n</p>
      </div>
      <div class="right">
        <p>r<br/>i<br/>g<br/>h<br/>t<br/><br/>c<br/>o<br/>l<br/>u<br/>m<br/>n</p>
      </div>
      <div class="more-right">
        <p>m<br/>o<br/>r<br/>e<br/><br/>r<br/>i<br/>g<br/>h<br/>t<br/><br/>c<br/>o<br/>l<br/>u<br/>m<br/>n</p>
      </div>
      <div class="center heightfix">
        <div class="center-no-left">
          <p>c<br/>e<br/>n<br/>t<br/>e<br/>r<br/><br/>c<br/>o<br/>n<br/>t<br/>e<br/>n<br/>t</p>
        </div>
      </div>
    </div>
  </div>
  </div>
  </div>
  </div>
  </div>
  </div>
  </div>
  <div class="bottom-box">
    <br/>bottom content<br/><br/>
  </div>
</div>
CSS Code
div.main-box {
position:relative;
width:80%;
margin:0 auto;
overflow:hidden;
background:#B0C1C1;
border:solid 10px #993333;
}
div.top-box {
background:#336666;
text-align:center;
text-transform:uppercase;
border-bottom:solid 10px #993333;
}
div.bottom-box {
background:#336699;
text-align:center;
text-transform:uppercase;
border-top:solid 10px #993333;
}
div.left-box {
position:relative;
width:100%;
left:25%;
background:#D0E1E1;
border-left:solid 10px #993333;
}
div.center-box {
position:relative;
width:100%;
left:100px;
background:#FFFFCC;
border-left:solid 10px #993333;
}
div.reset-left-box {
position:relative;
width:100%;
left:100%;
margin-left:-25%;
}
div.reset-box {
position:relative;
width:100%;
margin-left:-100px;
}
div.reset-right-box {
position:relative;
width:100%;
margin-left:-120px;
left:-100px;
}
div.more-right-box {
position:relative;
width:100%;
background:#D0EEC0;
border-left:solid 10px #993333;
left:-30px;
}
div.right-box {
position:relative;
width:100%;
margin-left:100px;
background:#B0CEA0;
border-left:solid 10px #993333;
left:-10px;
}
div.content-box {
position:relative;
width:100%;
margin-left:-100%;
left:120px;
}
div.left {
float:left;
width:25%;
text-transform:uppercase;
}
div.more-left {
float:left;
width:100px;
margin-left:10px;
text-transform:uppercase;
}
div.right {
float:right;
width:120px;
text-transform:uppercase;
}
div.more-right {
float:right;
width:100px;
text-transform:uppercase;
}
div.center-no-left {
margin-left:100px;
margin-right:100px;
padding-left:10px;
}
div.center {
margin-left:25%;
margin-right:120px;
padding-left:10px;
padding-right:10px;
text-transform:uppercase;
}
* html div.center-no-left {
height:1%;
margin:0;
}
* html div.more-left {
margin-right:-3px;
}
* html div.more-right {
margin-left:-3px;
}
.clearfix:after {
content: "."; 
display: block;
height: 0px;
clear: both; 
visibility: hidden;
}		
.heightfix:before {
content:'.';
display:block;
visibility:hidden;
height:0;
}

Notes


Layout issues

As always this solution has problems too. Until now I didn't find any problems apart from those with Netscape Navigator. I found a total of 3 issues with this browser, and solved the first two of them. The third one remains unsolved but I actually think there's a solution to this one too because of the particularity of the issue.

The Netscape Problem(s) -- Fixed with NN 9

As I mentioned above, with Netscape Browser (v 8.1.3) used with the option "Display like Firefox" enabled, when the whole layout is lower in height that the display area, the #main-box container will show a 1px of its background on the right. A solution to this is simply put an overflow: scroll for the html tag. You can see this in the style.css file used in all the 3 columns examples.

In addition there's another little problem (with Netscape, still, but used with the option "Display like IE") for which I found a solution. The problem comes up when you use named anchors inside the #left-box, #center-box or #right-box columns. That is, when you click on the link pointing to the named anchor, the browser jumps back to the clicked anchor. To solve this, simply set a tabindex attribute for the named anchor with the value of 0 as you can see in the working sample I provided above.

The unsolved issue concerns again named anchors. This behavior is a bit similiar to the one of the super-padding, apart from showing up only on Netscape and being less painful. In fact, when you have named anchors in your page, and you click on a link which points to the named anchor it works without problems. The problem show up only if you push the refresh button (having the named anchor selected in the url, for example http://somesite.com/somefile.html#mylink). Instead, if you push the GO button near the url, the browser displays the page correctly. I know it's a bit weird, but fortunately it is also ignorable because of its weirdness.

Note: The above issues are grayed because they've been solved with the new version of Netscape Navigator (Version 9.0) so I think now they're not important any more.


The more columns than I could

If you really understood my method, it shouldn't be difficult to guess how to add more columns. Although I think none will ever need more than 4 or 5 columns, for which I already provided examples, you could like to try some complex layout with 10 columns (for example) to wonder how flexible the method is or for teaching purposes.

As you should have learnt reading the article, the layout base concept is to relatively shift and unshift (reset) the position. So when you make a change (a movement of a container), you need somewhere a way to reset that change (that is, to cancel the movement). So, theorically speaking, you need two values (margin-left and left) which let you move two different containers (not the same one, otherwise you completely hide the change). One container to add the column, and an additional transparent (one that doesn't cover the layout with its colors) container to adjust the layout positions. In conclusion, if you remove the center, which is not really a column but a filler, the real columns you have require one value for themselfes and another one in some other container to restore the position. In addition you need an additional value to reset the space used by left-borders, which you can put in the last container used and another one for right borders if you have more than 1 right column.

I made a calculation, which is probabily wrong, to obtain the number of containers needed in addition to the usual ones when the layout has more than 3 columns. As I said, I'm sure it's wrong/inexact, but gives a general idea on how many containers you need for a given number of columns: you have to double the total number of real columns (that is, the layout columns less 1, the center) and add 1. For example, for 4-columns layout, you need ((4-1)*2)+1 = 7 containers; for 5-columns layout you need ((5-1)*2)+1 = 9 containers and so on.