Dark Refraction

Creating a Three Column Layout with CSS

Getting CSS to layout your pages the way you want it to can be tricky. This is how I sometimes create a three column layout for my sites.

What I wanted, basically, was to have two fixed-width columns on ether side of the page's content, and then the content itself in the center, which can change width along with the screen size. I also wanted to give the content a maximum width so it doesn't expand too far for people with large screens.

You can view a live sample here.

This is the HTML body of the layout:

<body>

<div class="columns">
    <div class="rightcolumn">
        This is the righthand column.
    </div>

    <div class="leftcolumn">
        This is the lefthand column.
    </div>

    <div class="content">
        This is the main content.
    </div>
</div>

</body>

I think that's pretty self explanatory.

The CSS is where all the magic happens, so I'll break it down a bit for you.

I'll start with the CSS for the columns:

.rightcolumn,
.leftcolumn {
    width: 160px;
    position: absolute;
}

.rightcolumn {
    right:  0px;
}

.leftcolumn {
    left: 0px;
}

Obviously, the width line simply sets the width of each of the columns.

The trick here is setting position: absolute;, and then the left and right distances for each of the respective columns. Normally, this would position the columns all the way at the left and right edges of the screen, but in this case it doesn't.

The CSS spec states:

If the element has position: absolute, the containing block is established by the nearest ancestor with a position of absolute, relative or fixed, in the following way:

  1. In the case that the ancestor is an inline element, the containing block is the bounding box around the padding boxes of the first and the last inline boxes generated for that element. In CSS 2.1, if the inline element is split across multiple lines, the containing block is undefined.
  2. Otherwise, the containing block is formed by the padding edge of the ancestor.

This means that we can make the divs be positioned at the left and right edges of the containing <div>, not the left and right edges of the screen if we simply set position: relative on the container, like this:

.columns {
    position: relative;

    padding-left:  180px;
    padding-right: 180px;

    max-width: 800px;

    margin-left: auto;
    margin-right: auto;
}

The position: relative; line doesn't do anything else, because we don't change the position at all.

Setting the padding on the left and right reserves space for each of the columns. Otherwise the columns would overlap the main content, which is not what we want.

Note that the padding on each side is set to 180px, while the column's css set the width to 160px. This gives us 20 pixels of space between the right and left columns and the page's content.

Setting max-width simply limits the size of the layout. This makes the maximum size of the entire layout 800 + 180 * 2, or 1160 pixels.

Setting margin-left and margin-right to auto centers the <div>.

body {
    margin: 5px;
    min-width: 620px;
}

Finally, for the body element, we add margins so the columns aren't directly against the edges of the screen when the screen is less than 1160 pixels wide. We also set the min-width property because we don't want to let the content shrink down to too small of a column, or the text will be a pain to read.

In the end this is all of our CSS put together:

.rightcolumn,
.leftcolumn {
    width: 160px;
    position: absolute;
}

.rightcolumn {
    right:  0px;
}

.leftcolumn {
    left: 0px;
}

.columns {
    position: relative;

    padding-left:  180px;
    padding-right: 180px;

    max-width: 800px;

    margin-left: auto;
    margin-right: auto;
}

body {
    margin: 5px;
    min-width: 620px;
}

One nice things about this layout are that if you shrink the browser window, it still looks reasonable. Only if you go to a screen size less than ~640 pixels wide do you ever need horizontal scrolling. For mobile devices, it's best to switch to a different layout.

On a final, <sarcasm> happy </sarcasm> note, I'd like to point out that this example will trigger a number of bugs in earlier versions of Internet Explorer. I haven't actually tried it out, but I know there are at least two bugs that will screw up this layout on IE. I, for one, am sick of putting up with IE 6's crap, so I have left working around these bugs as an exercize for the reader.

If you actually care about IE users, then I feel terribly sorry for you.