Pushing the Limits (Part 1): The Perfectly Semantic Three Column CSS Layout

July 7th, 2008 in Design Tips & Tutorials

by: Matthew Griffin

Building a three or four column layout on the web without the help of a table can be a difficult task. The CSS3 spec proposes a perfectly tailored solution; but, unfortunately, CSS3 support is spotty at best even in modern browsers. We're stuck with CSS2 until that changes, so we might as well make the best of it. There are a number of ways to overcome the lack of multi-column support in CSS and none of them is very pretty.  The three-column layout is the easiest to achieve without stepping outside the semantic boundaries, so we'll start there. Then in the next few articles we'll move on to the rarely explored waters of four-column+ CSS layouts.

The Problem with the Three-Column Layout

The problem we run into when attempting to build a semantically correct three column layout is that CSS only provides two attribute values for positioning relatively positioned block-level elements horizontally. Those two attribute values are, of course: float: right and float: left. To build a two column layout, then, all you have to do is create two <div> tag pairs and float one right and the other left. Viola, a two column layout.

Try to take a step up to the three-column layout, though, and you will quickly find that there is no such thing as float: center. But take heart—there is a semantically correct solution that will get the job done. No need to run back to <table> tags or, worse yet, a semantically incorrect usage of unordered lists.

Getting Your XHTML markup ready

We'll start our example with a snippet of semantically correct XHTML (it will validate as HTML 4.01 as well) markup for our content. The end product will be a fixed-width three column layout and you can see it/steal it here. Our markup will include a header, three <div>s for content , and a footer <div>. Here's how it looks:

<div id="wrapper">

    <h1>My Personal Homepage</h1>

    <div id="navigation">

    <div id="sidebar">

    <div id="content">

    <div id="footer">
        Thanks for stopping by my personal home page! Come back soon!


Just as a side note: notice that each of the three-columns is given an id that describes the type of content it holds, rather than its position on the screen. This type of identification makes it easy to navigate the markup and easy to alter the layout in the future without turning your ids into nonsense. For example, if you named your navigation column "leftcolumn" and in the future you wanted the navigation to be on the right; you could easily make the change in your stylesheet, but the id would no longer make sense. If you want to take it a step further, you can label the columns even more generic names like "sidebar1" and "sidebar2"; but I find that it's rare that the content in a navigation <div> changes to something non-navigation.

Using CSS to Style Your Columns into Submission

Now that we have a nice, light-weight page marked up, we'll add some CSS to horizontally align our columns. The final product we are shooting for is a centered, fixed-width, three-column layout; so we'll start by setting a reasonable width for the "container" <div> and centering it. Next, we're going to set the widths of our two sidebar columns (called "sidebar" and "navigation") and float one to the left and one to the right. When we're finished, the "content" <div> will slide right up between our two sidebars to form the middle column in our three-column layout. Here's what the CSS looks like:

body {
    font: 1em Verdana, Arial, Helvetica, sans-serif;
    background: #ccc;
    color: #000;
    text-align: center; /* Centers the container */
    margin: 0;
    padding: 0;

#wrapper {
    width: 780px; /* 780px is just wide enough to fill and 800px screen */
    margin: 0 auto; /* It's important to set the margin to auto if you want the layout to center */
    background: #fff;
    text-align: left;
    border: 1px solid #999;

#header, #sidebar, #navigation, #footer, #content {
    padding: 10px;  /* This sets a 10px padding on all of our content boxes */

#header {
    background: #999;
    margin: 0;
    padding 0;

#sidebar {
    float: left; /* Sets this column to the left */
    background: #ccc;
    width: 160px;

#navigation {
    float: right; /*Sets this column to the right */
    background: #ccc;
    width: 160px;

#content {
    margin: 0 190px; /* Sets the margin to 190px on the right and left */

#footer {
    background: #999;
    clear: both;

Again, a full working example is available here if you want to see it in action. The CSS is in the <header> of the file to make it easier to read. This first solution to the 3+ column CSS layout issue is by far the easiest and most semantic solution available. Unfortunately, when you get past three columns, it starts to get a little stinkier. Next week, we'll look at one four-column CSS layout technique.

Some Final Notes

The example is free for copying but there are a few things I should point out before you run with it. First, in my markup, I didn't put <p> tags or any other semantic tags around the content that appears in the various content boxes. I did this so we could focus on the layout; but in reality, you should put semantically correct tags around all of your content.

Also, the example will work perfectly in all modern standards-compliant browsers and IE at least as far back as version 5.5. However, I specifically avoided markup that would be susceptible to IE box model bugs that appeared pre IE7. Just be warned that if you mess with the padding and markup very much, the layout may break in IE6 and earlier.



Posted By: David Hund on 07/08/08

Hi Matthew, enjoying the new look and recent articles. Thanks! The title of this article, I find, is a little misleading though: "Pushing the Limits"? The solution you come up with is nice, but there have been many creative solutions to this problem that might have been good to point out. What makes this solution 'the holy grail' ? (pun intended) I might have just missed the point. One of my favourites (because of it's simplicity) is either floating all 3 columns to the left. Or wrapping 2 columns in a wrapper that floats opposite to column1. OK. 1 extra wrapper :-) Anyway, I don't mean to criticize your article. I enjoyed reading it. I just think that when you touch on the subject of 3-column layouts it might have been a good idea to also mention some of the gazillion attempts/solutions that have been made. It would be very beneficial to see a comparison: pro's and con's of each... http://www.alistapart.com/articles/holygrail and its comments is a nice startingpoint. Thanks.

Posted By: Matthew Griffin on 07/08/08

David, thanks for the comments. I guess I can see where "perfectly semantic" could be taken to mean the holy grail of multi-column. That wasn't really my intention though. I simply meant to contrast this technique against the hundreds of possible solutions that are not semantically correct. As I mentioned, I'll be writing about at least two more multi-column layout techniques in the next few weeks. All of them have pros and cons.

Posted By: alphadog on 07/08/08

Minor markup nitpick: I hate fixed layouts. For example, I usually read blogs in FF in a pivoted LCD. So, your assumption of a fixed 780px to satisfy most monitors fails on my non-standard 768x1024 (minus some for browser chrome) browser window. I have to always scroll a little right to read your articles.

Posted By: Matthew Grffin on 07/08/08

alphadog, I think that's the perennial struggle of the web designer--trying to build a layout that give maximum control while breaking in the fewest number of browser/monitor combinations. Thanks for the comment.

Posted By: Gavin Kistner on 09/07/08

I love that you've taken the time to write this up and share it, but I strongly disagree with this being "perfectly semantic". Unless I'm missing something, your solution here requires the navigation and sidebar elements to appear in HTML before the content. In my opinion, a proper semantic ordering of elements as would be desired by a screen reader would place the content before the sidebar, and that before the navigation.

Posted By: Matthew Grffin on 09/16/08

Hmmm... good point, Gavin. I agree.

Posted By: PHP developer on 09/20/08

Such markup has several cons: 1) if columns has different colors and #content is more high, columns looks like blocks, not columns: bg of central column is seen below. 2) no resizing 3) if you need to use floating content in central column, you can't use nor clear:left nor clear:right because it put block below side column. It seems as not too necessary but in practice should be very useful: it allow you to use all screen wide with showing images/links in several columns inside content block. All that was necessary with tables: to set loat:left;width:100px for links and then clear:left for following below header. Now I see it impossible in semantic html. you can see examples of what I'm saing about in http://avtoopt.com.ua/

Posted By: Clubturk.net-2. Seo Yarismasi on 04/27/09

I hate fixed layouts.

Post Your Comment

Comments are closed.