Easy CSS Layouts

Get rid of table soup

Felix Plesoianu

felix.plesoianu.ro

Part 1 — Introduction

One thing I hear often from people making Web pages is that CSS-based layouts are too difficult. The usual reasons given are browser quirks and/or CSS limitations.

I will demonstrate how the most typical website layout can be trivially implemented in CSS, whitout ever running into said quirks.

The advantages are: less work for the designer; less work for the programmer (where applicable) and much better search engine indexing thanks to semantic markup.

Getting started

Here's a wireframe of our layout and the code to create it (try1.html).

<html>
 <head>
  <title>CSS Layout demo</title>
  <style type="text/css">
   body { Margin: 0; Padding: 1%; }
   .area { Border: 1px solid black; }
   .main { Height: 60%; Float: left; }
   #header { Height: 20%; }
   #sidebar1 { Width: 20%; }
   #content { Width: 59%; }
   #sidebar2 { Width: 20%; }
   #footer { Clear: both; Height: 20%; }
  </style>
 </head>

 <body>
  <div class="area" id="header">Header</div>
  <div class="main area" id="sidebar1">Sidebar 1</div>
  <div class="main area" id="content">Content</div>
  <div class="main area" id="sidebar2">Sidebar 2</div>
  <div class="area" id="footer">Footer</div>
 </body>
</html>
 

As you can see, it's the stereotypical header-footer-three column thing.

The wireframe explained

I will assume you're already used to CSS (and HTML). Just let me highlight a few key details:

But wait, there's a glitch on the right side! How do we fix it?

Lining up boxes

It's actually very simple: just float #sidebar2 to the right (try2.html).

<html>
 <head>
  <title>CSS Layout demo</title>
  <style type="text/css">
   body { Margin: 0; Padding: 1%; }
   .area { Border: 1px solid black; }
   .main { Height: 60%; Float: left; }
   #header { Height: 20%; }
   #sidebar1 { Width: 20%; }
   #content { Width: 59%; Border: none; }
   #sidebar2 { Width: 20%; Float: right; }
   #footer { Clear: both; Height: 20%; }
  </style>
 </head>

 <body>
  <div class="area" id="header">Header</div>
  <div class="main area" id="sidebar1">Sidebar 1</div>
  <div class="main area" id="content">Content</div>
  <div class="main area" id="sidebar2">Sidebar 2</div>
  <div class="area" id="footer">Footer</div>
 </body>
</html>
 

But now there's a visible gap; lose the content's border to hide it.

Fixing the fix

We could have tried other methods, too:

For now, let's go on. I'd like to show you another neat trick.

What if you want to put #sidebar1 on the right and vice-versa?

Reversing column order

Oh no, I hear you groan, we have to move around all that content...

<html>
 <head>
  <title>CSS Layout demo</title>
  <style type="text/css">
   body { Margin: 0; Padding: 1%; }
   .area { Border: 1px solid black; }
   .main { Height: 60%; Float: right; }
   #header { Height: 20%; }
   #sidebar1 { Width: 20%; }
   #content { Width: 59%; Border: none; }
   #sidebar2 { Width: 20%; Float: left; }
   #footer { Clear: both; Height: 20%; }
  </style>
 </head>

 <body>
  <div class="area" id="header">Header</div>
  <div class="main area" id="sidebar1">Sidebar 1</div>
  <div class="main area" id="content">Content</div>
  <div class="main area" id="sidebar2">Sidebar 2</div>
  <div class="area" id="footer">Footer</div>
 </body>
</html>
 

...or simply change two lines of CSS (try3.html). Try that with tables!

Spacing things up

Don't those boxes look ugly with no margins and no padding?

<html>
 <head>
  <title>CSS Layout demo</title>
  <style type="text/css">
   body { Margin: 0; Padding: 1%; }
   .area { Border: 1px solid black; Margin:1em; Padding: 1em; }
   .main { Height: 60%; Float: left;}
   #header { Height: 20%; }
   #sidebar1 { Width: 20%; }
   #content { Width: 59%; Border: none; }
   #sidebar2 { Width: 20%; Float: right; }
   #footer { Clear: both; Height: 20%; }
  </style>
 </head>

 <body>
  <div class="area" id="header">Header</div>
  <div class="main area" id="sidebar1">Sidebar 1</div>
  <div class="main area" id="content">Content</div>
  <div class="main area" id="sidebar2">Sidebar 2</div>
  <div class="area" id="footer">Footer</div>
 </body>
</html>
 

With them, on the other hand, the whole layout goes haywire.

A CSS box model reminder

What just happened?

According to the CSS specification, the margins and paddings add to the requested size as opposed to subtracting from it.

We could tweak the percentages, but this would open a brand new can of worms.

Spacing things up done right

The solution: leave the layout boxes alone; pad what's inside!

<html>
 <head>
  <title>CSS Layout demo</title>
  <style type="text/css">
   body { Margin: 0; Padding: 1%; }
   .area { Border: 1px dotted red; }
   .scaffold { Border: 1px solid black; Margin: 1em; Padding: 1em; }
   .main { Height: 60%; Float: left; }
   #header { Height: 20%; }
   #sidebar1 { Width: 20%; }
   #content { Width: 59%; Border: none; }
   #sidebar2 { Width: 20%; Float: right; }
   #footer { Clear: both; Height: 20%; }
  </style>
 </head>

 <body>
  <div class="area" id="header"><div class="scaffold">Header</div></div>
  <div class="main area" id="sidebar1"><div class="scaffold">Sidebar 1</div></div>
  <div class="main area" id="content"><div class="scaffold">Content</div></div>
  <div class="main area" id="sidebar2"><div class="scaffold">Sidebar 2</div></div>
  <div class="area" id="footer"><div class="scaffold">Footer</div></div>
 </body>
</html>
 

Note: only now we're starting to add more markup (try5.html).

Part 2 — The real thing

In part one you have learned a simple technique for laying out a Web page with CSS.

In part 2 I will show how a realistic site can be created with the same means.

Adding backgrounds and borders is a bit more complex, but still easier than with tables.

The wireframe revisited

For part 2 we'll use the following file: try6.html...

body { Margin: 0; Padding: 0; }
#main .area { Float: left; }
#sidebar1, #sidebar2 { Width: 25%; }
#content { Width: 50%; }
.guard { Clear: both; Height: 0; }
#footer { Clear: both; }
#main { Margin: 0 1px; } /* Make IE6 behave */
 

...to which we'll incrementally add CSS, starting with try6.css.

Notes on the realistic wireframe

Before we go on, let's see what we've got.

A perfectly good fluid layout

Time to make it look nicer. Add try7.css to the example file.

body { Background-color: #eeffff; }
#header .scaffold {
	Margin: 2em;
	Padding: 1em;
	Border: 3px groove #ffcc00;
	
	Margin-bottom: 0;
	Border-bottom: none;
	
	Background-color: #eeffee;
}
#main {
	Margin-left: 2em;
	Margin-right: 2em;
	Border-left: 3px groove #ffcc00;
	Border-right: 3px groove #ffcc00;
}
#main .scaffold { Padding: 1em; }
h2 {
	Padding-left: 0.5em;
	Background-color: #336600;
	Color: #ffffff;
}
#content  { Background-color: #ffffee; }
#footer .scaffold {
	Margin: 2em; Padding: 1em;
	Border: 3px groove #ffcc00;
	
	Margin-top: 0;
	Border-top: none;
	
	Background-color: #663300;
	Color: #ffffff;
	Text-align: center;
}
#footer .scaffold a { Color: #ffff00; }
 

Make sure it comes after the existing rules.

Fluid layout highlights

Fixed layouts work as well

Just add try8.css to the example file.

#header .scaffold, #main, #footer .scaffold {
	Width: 800px;
	Margin-left: auto;
	Margin-right: auto;
}
#header .scaffold, #footer .scaffold { Padding-left: 0; Padding-right: 0; }
h1, #footer p { Padding-left: 1em; Padding-right: 1em; }
 

Again, make sure the new CSS comes last.

That's it?

Before the end, let's see two more nice effects you can use as starting points in your CSS explorations.

A dropdown menu system

Let's turn the navbar into a windows-style menubar.

/* Enable dropdown behavior. */
#navbar dl { Float: left; }
#navbar dd { Display: none; }
#navbar dl:hover dd { Display: block; }

/* Position the menubar. */
#navbar {
	Position: absolute;
	Top: 5em;
	Left: 50%;
}

/* Make it look right. */
#navbar dl {
	Width: 7em;
	Background-color: #ffcc00;
}
#navbar dd {
	Margin: 0;
	Padding: 0;
	Border: 2px outset #ffcc00;
}
#navbar a {
	Display: block; /* Increase the mouse target area. */
	Text-decoration: none;
	Color: black;
	Font-weight: bold;
}
#nabvar a:hover {
	Color: #ffcc00;
	Background-color: black;
}
 

No, don't change the HTML: adding try9.css is enough.

Comments on the menubar

Multiple-column listings

You know, like when you have an e-commerce site with lots of products.

.entry-list, .entry-list .scaffold {
	Margin: 0.5em;
	Padding: 0.5em;
	Border: 1px solid black;
}
.entry-list {
	Margin: 1em;
}
.entry {
	Float: left;
}
#one-column .entry {
	Width: 100%;
}
#two-columns .entry {
	Width: 50%;
}
#three-columns .entry {
	Width: 33%;
}
 

This time get try10.html along with try10.css.

And my point is...

Conclusions

Credits

Beta testers:

Software used for this presentation: