This is an intermediate level tutorial and is a continuation of a previous tutorial that can be found here. It assumes the reader has a good knowledge and understanding of HTML and CSS.

Introduction

In our previous tutorial, we saw how we can create multi-column layouts using semantic markup and CSS to manipulate containers. The methods we used required no workarounds, hacks or browser specific treatments. Here, we'll continue with that by examining how to overcome the technique's shortcomings and pitfalls without upsetting the layout.

Here are the markup and CSS that we were left with at the end of the previous tutorial.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>    
    <title>My Website</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
</head>
 
<body>
<div id="page_container">
    <div id="header">
        <h1>My Web Site</h1>
    </div>
    <div id="left_column">
        <ul>
            <li><a href="#">Menu 1</a></li>
            <li><a href="#">Menu 2</a></li>
            <li><a href="#">Menu 3</a></li>
        </ul>
    </div>
    <div id="center_column">
        <h2>My Document</h2>
        <p>Vivamus elementum ligula gravida neque. Cras adipiscing ligula non turpis. Sed cursus scelerisque libero. Sed at arcu. Vestibulum metus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Phasellus id turpis. Sed purus. Integer eget ligula elementum felis aliquet rhoncus. Morbi augue.</p>
    </div>
    <div id="right_column">
        <h3>Sidebar</h3>
        <p>Vivamus non urna eget nisi placerat vehicula. Vivamus semper molestie lacus. Proin a tellus et massa placerat ultricies. Curabitur viverra convallis felis.</p>
    </div>
    <div id="footer">
        <p>Copyright Information</p>
    </div>
</div>
</body>
</html>
/* Intrinsic HTML Elements */
body{margin:0;padding:0;}
div{margin:0;padding:0;}
h1, h2, h3, p{margin:0;padding:10px;}
ul{margin:0;padding:0;}
li{list-style-type:none;padding:10px;}
 
/* Uniquely Identified Containers */
#page_container{width:760px;margin:0 auto;}
#header{background:#999;}
#left_column{width:180px;float:left;background:#CCC;}
#center_column{width:400px;float:left;background:#ECECEC;}
#right_column{width:180px;float:left;background:#CCC;}
#footer{clear:both;background:#999;}

Currently, our document should render almost identically in all *current browsers (Figure 1).

Figure 1 - Rendered markup and CSS (Opera 9.26)

*By "current", I'm refering loosely to Internet Explorer 7, Firefox 2, Opera 9 and Safari 3. The current version of Konquorer should be added to this list, however, I do not have access to this browser.

Working with the Content-Box Box Model and Padding

The first thing we need to discuss and understand is the box model. Understanding this is important whenever we define a fixed pixel width for a block-level element. In this case, the <div> elements that we use for columns.

The are two types of box models, the "content-box" and the "border-box". The difference between them is how we regard their dimensions. Where the width of a border-box is measured form border to border, a content-box is measured in terms of the content area. This is illustrated below (Figures 2 and 3).

Figure 2 - The border-box

Figure 3 - The content-box

The box model most widely supported today is the content-box.

Because we've defined specific widths for the columns, we don't want to touch their padding or margining. Expanding these would, in effect, expand the cumulative width of the column and cause our columns to wrap. Therefore, we normalize these by setting them to "0".

To rephrase this idea; If I create a content-box and set it's width to 200 pixels, then added 10 pixels of padding on all sides, the box would render visually as 220 pixels.

While it may seem counter-intuitive, instead of apply padding once to the container, we apply it to the textual items within. Those elements haven't been given specific widths and, therefore, conform naturally to the container's content area. This was the last bit of CSS we added in the previous tutorial.

h1, h2, h3, p{margin:0;padding:10px;}

We could, of course, be more specific with the dimensions of our padding by specifying top, right, bottom and left dimensions. Let's do this, temporarily, with the <li> element using the shorthand notation.

li{list-style-type:none;padding:5px 10px 5px 10px;}

"How do I get all the columns to expand equally?"

The short answer is, "We don't." What we do, though, is create the illusion that this is occuring by using a graphical background. We don't apply the background to each column, individually. Instead, we apply a single background image to the parent container. In this case, the <div> identified as "page_conatiner". In Figure 4, we see what the resulting background will look like. To make this happen, we'll need to create, or obtain, a graphic that is 760 pixels wide and 1 pixel tall.

Figure 4 - Background design

In the CSS, we can remove the solid colors we specified earlier for the columns.

#left_column{width:180px;float:left;}
#center_column{width:400px;float:left;}
#right_column{width:180px;float:left;}

Next, we'll apply our graphic which by default will repeat, or tile.

#page_container{width:760px;margin:0 auto;background:url(background.gif);}

When we render the page, it appears as though the columns expand vertically and equally, regardless of who much content we have in any given column.

Figure 5 - Rendered with page_container background (Opera 9.26)

Working With the <ul> as a Menu

The next thing we'll look at is the menu. The reasons for using unsorted lists as a menu and the advanced manipulation of them would be a good topic for a tutorial, however it is not in the scope of this one.

Modifying a <ul> used as a menu seems to be a stumbling block for many of us. Typically, the goal of styling the menu is to have each link stretch accross the horizontal width of the column. In addition, we'd like for the user's cursor to interact with the entire area as well.

The goal is achieved, simply, by instructing those links to render as block-level items, as opposed to inline-level items. We'll also reduce the padding of the <li> containers to "0" and instead add the desired padding the <a> elements. We'll be creating one new selector in our CSS.

li{list-style-type:none;padding:0;}
li a{display:block;background:#CCC;padding:5px 10px 5px 10px;}

For the purpose of seeing the cursor interactions, we'll add yet another new selector, as well - a psuedo-state of the <a> element.

li a:hover{background:#F00;}

Figure 6 - Final render (Opera 9.26)

Conclusion

In this tutorial we've seen how to construct and maintain a three column layout using semantic markup and CSS - without workarounds. In addition, we've explored how to overcome common errors that would, otherwise, break our layout.

While this tutorial did not address it, the same technique can be applied to percentage based layouts.

Please PM me with any suggestions for improving this tutorial.

Thanks!
dM

This page was published on It was last revised on

0

11 Comments

  • Votes
  • Oldest
  • Latest
Commented
Updated

Yeah, Great Tutorial. Thanks DM! Will there be Part-3? -- It's irresistible.

add a comment
0
Commented
Updated

Hmmm. I hadn't thought of a part 3. I'm not sure where to go with this. Let me think on it George. 😉

add a comment
0
Commented
Updated

Hi dM, Good Day, 🙂
I have some questions. Let us say, the background image not repeat, making it center or position some where else(left, right). How would you recommend that I do it?

If we have many pages, would you recommend that I copy and paste from my first page HTML? say I have more than 50 links pages. (or even more). As far as web page layout consistency is concerned, how would you recommend us to do? Your time is highly appreciated.

Thank you very much,
g.

add a comment
0
Commented
Updated

...Let us say, the background image not repeat, making it center or position some where else(left, right). How would you recommend that I do it?

The background image in the "page_container" element, or any container, can be manipulated in several ways by adding directives to the "background" definition.

Within the general "background" definition(s) you can define

  • a solid color
  • an image
  • how the image repeats, or doesn't
  • how the image reacts in a scrolling space
  • the vertical placement of the image by alignment or by pixel measurement
  • the horizontal placement of the image by alignment or by pixel measurement
#page_container{
	background-attachment: fixed;
	background-color: #FFFFFF;
	background0image:url(background.gif)
	background-repeat: no-repeat;
	background-position: center 20px;
}

This can also be accomplished with a shorthand notation...

#page_container{background:url(background.gif) fixed no-repeat center 20px #FFF;

(I didn't test this, but it's close enough for an example)

If we have many pages, would you recommend that I copy and paste from my first page HTML? say I have more than 50 links pages. (or even more). As far as web page layout consistency is concerned, how would you recommend us to do? Your time is highly appreciated.

I recommend that site wide styles are always housed in a single file, whenever possible. If variations are required within a site, I suggest that the varying definitions are given their own style sheets and loaded additionally per page.

Here's an example...

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>My HTML Document</title>
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
<link href="master.css" type="text/css" rel="stylesheet" media="screen" />
<link href="uniqueForThisPage.css" type="text/css" rel="stylesheet" media="screen" />
</head>
add a comment
0
Commented
Updated

I recommend that site wide styles are always housed in a single file, whenever possible. If variations are required within a site, I suggest that the varying definitions are given their own style sheets and loaded additionally per page.

Here's an example...

 
Line number On/Off
Code: Select all
 
   1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   2. <html xmlns="http://www.w3.org/1999/xhtml">
   3. <head>
   4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   5. <title>My HTML Document</title>
   6. <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
   7. <link href="master.css" type="text/css" rel="stylesheet" media="screen" />
   8. <link href="uniqueForThisPage.css" type="text/css" rel="stylesheet" media="screen" />
   9. </head>
 

I can not understand this part. A tutorial about duplicating similar pages would be useful in my opinion. However, it is up to the moderator to decide. Thanks again to this nice tutorial.

add a comment
0
Commented
Updated

Wow! I didn't know I'd be treated to a tutorial like this when I joined this site. The best CSS tutorial I've come across. Maybe it's your method of instruction but I didn't have time to do a tutorial and did it anyway!

Advanced menu manipulation would be a great way to continue.

One thing that did bother me was the white space to either side of the container. If you wanted to access that space for design or added functionality how would you do it?

Hey, thanks. I'll definitely be looking for more from you.

add a comment
0
Commented
Updated

This is one of the best tutorials on CSS layout that I've read! Thank you!

I'm having trouble seeing the background image of the #page_container in Firefox. I can see it if I set a height for the #page_container, but otherwise it doesn't show. Any guesses as to what's happening?

Thanks so much again!

add a comment
0
Commented
Updated

If there isn't a 'clear:both;' object in the parent container, the container won't accrue height from the 3 columns because they've left the render flow. I was accomplishing this with the #footer.

Do you have the footer? Is it inside the #page_container div?

If none of this seems right, please post your markup so I can look.

...and thanks for the compliment. I'm glad people get something out of this. 🙂

add a comment
0
Commented
Updated

I did indeed have a footer with clear:both. However, it also had a float on it, which seems to break things. When I took the float out, it worked fine!

So, you have to have at least one object with clear and no float, is that right?

...and you're very welcome. I'm a teacher, myself. So I know good teaching. And you've got it! You're wonderful at breaking it down. If you're ever in SF and need a job, I'm the director of training at a school called Learn iT. Look me up!

-David

add a comment
0
Commented
Updated

Thanks again, David.

Yes, the float directive will cause an object to be discounted in the normal flow of the page. The clear directive causes an object to show regard for the floated ones and will affect the container as well.

Glad you got it fixed!

add a comment
0
BO
443 9
Commented
Updated

Part 3 could be making the layout as a percentage and not a fixed width. That would be useful.

add a comment
0