Friday, August 24, 2007

Cross-browser pure-CSS table-less layouts

[Note: this is a draft article with major revisions ahead for it, but I prefer to leave it visible for comments during this time.]

When it comes to web design, I see more questions and confusion about how to control block-element positioning, sizing, and alignment than about just about anything else, This can certainly be frustrating, especially when it comes to maintain identical formatting across browsers. Here is my attempt at offering a few tips that will hopefully make life just a little easier for people struggling with this.

The layout I'll use for this article features a fixed-height header, 3 columns that will always stretch to the window's height, a centered "menu bar" at the top of the middle column, and a fixed-height footer at the bottom of the page. The LH column has a fixed width of 200px, the content column (middle) is 800px, and the RH column is elastic and will occupy whatever space remains.
Here is the concept:






Appearance:


Nesting structure:



To see the example in action...

The XHTML
The Stylesheet

So presuming you want to ditch your old table layouts, here are the things that have simplified the process the most for me. First off, commit not to give up too soon on making one valid css work for everything. If you must resort to ugly IE or Firefox hacks, exhaust your other options first! You all know what I mean... text-align:-moz-center, malformed CSS that IE will see but Firefox won't, using server-side tricks to serve different stylesheets to different browsers, etc. Shame on you! Okay, just kidding... I've done it too and do it even in this example. The point of this, though, is that if hacks like this are your *first* resort, your stylesheet is going to become needlessly hard to manage. The point of this posting is to point out that it is possible to get a page to display properly with minimal nesting of divs, without using tables, and with less CSS-mangling than you might think to pacify non-compliant browsers. So, can you imagine an easier coding experience with me?

Here are what I consider a few of the most important guidelines for wrangling your layout into obedience:

  • Always use the XHTML Transitional or Strict doctype declaration; this alone remedies many IE irregularities, especially for IE6;
  • Don't forget to include the xmlns attribute on your html element;
  • Don't use text-align:center; to center block level elements; follow the two rules above then see what margin: 0 auto; does (yes, even in IE6!);
  • Vertical stretch not working? Add height=100% attributes to your html and body elements;
  • Keep your layout blocks as direct children of the body element. Giving in and nesting your divs too soon only makes it harder to sort things out and fix them down the road;
  • Be judicious in your use of padding... it expands the size of your block elements, complicating the math you need to do to fix overlap issues.
  • Instead of padding, use a margin on your inner containers (like p elements).
  • Set up .center, .left and .right classes for text alignment and then always explicitly align your p elements; do not leave this to chance.
  • Control block-level alignment via elements themselves, not their containers...
  •   Use margin-right:auto; to align a div to the left within its parent container.
  •   Use margin-left:auto; to align a div to the right within its parent container.
  •   Use margin:0 auto; to center align a div within its parent container.


Now for some explanation of the stylesheet I used here:

/*
Only two IE hacks are used in this stylesheet:
1) *height for IE6 vs min-height for Firefox;
2) clear for Firefox vs. *clear for IE6
3) Nesting is used minimally in the HTML, while preserving proper sequence of elements:
Body (gray)
Container for LH & CONTENT divs (blue)
LH div (transparent)
CONTENT div (green)
RH div (transparent)
Empty float-clearing div
FOOTER div (black)
*/
html {
position:absolute;
height:100%;
font-family:Calibri, Arial;
}
body {
/* the body element actuall provides the color for our RH flanking div */
background-color:silver;
margin:0px;
padding:0px;
border:none;
width:100%;
}
div {
border:dotted 1px orange;
}
h1, h2, h3, p {
/* adding a margin to the text elements avoids having to add padding to their containers */
margin:10px;
border:dotted 1px blue;
}
#head {
width:100%;
height:30px;
text-align:center;
background-color:black;
color:#EDEDED;
}
#contentandlh {
/* making the container a float allows it to resize to accommodate child floats */
float:left;
clear:left;
background-color:#aabbff;
}
#lh {
float:left;
margin:0px;
padding:0px;
*height:100%;
min-height:100%;
width:200px;
}
#content {
float:left;
/* float left keeps firefox from leaving a gap with blue showing below the content div, since floats expand to accommodate child floats */
width:800px;
*height:100%;
min-height:100%;
background-color:#eeffee;
}
#rh {
margin-left:0 auto;
text-align:right;
}
#foot {
width:100%;
height:25px;
text-align:center;
background-color:black;
color:#EDEDED;
}
.post {
width:450px;
background-color:white;
margin:0 auto;
}
.quote {
width:400px;
margin:0 auto;
text-align:center;
background-color:#DDFFDD;
color:#222222;
}
.menu {
margin:0 auto;
width:600px;
text-align:left;
background-color:#333333;
color:orange;
}
.clear
{
/* without this hack, IE6 will create a vertical gap after the clear */
clear: left;
*clear: right;
margin: 0;
height:0px;
width:0px; }

Copyleft 2007, Rare But Serious Side Effects and Paul C Smith

First Post

Thank you for reading my first post. It's not meant to be interesting, but hopefully future ones will.