Positioning

Main column

This box hasn't been positioned - it is still a statically-placed element in the flow of the HTML document. The CSS for this block (which has been given the id “main” is:

  #main {
    margin-left: 275px; margin-right: 25px;
    padding: 5px;
    border: 1px solid black;
  }

Setting the margin in this way ensures that the main column never overlaps the side panel. The same can also be acheived by using absolute positioning on both items. However, positioned items are lifted out of the normal document flow, so the advantage of leaving #main as a static item is that you can place text and other elements after it. What that really means is that, if both boxes on this page were positioned using “position: absolute”, then <body> would end just after the title ("Positioning") - both columns would overflow it.

Units

This example uses pixels, but there are several other units that can be used. If your stylesheet is for printing, then pixels aren't recommended. You can also use ems (unit: em), percent of the containing block (so in this case, the width or height of <body>, whichever is appropriate) whose unit is the % sign, even traditional units such as points (unit: pt. There are 72 points per inch), centimeters (unit: cm), etc. etc.

Using percentages may surprise you every now and then. If you specify a width of 100% of the browser window, note that this is the full width, and by default the <body> element has margins and/or padding around the inside. Set them both to 0px unless you want to see scroll-bars.

As a general rule, do not mix units when positioning items, you'll end up tearing your hair out in frustration when boxes start overlapping, or showing up in unexpected places. The best general purpose units are pixels, percent and ems. And despite the warning, don't be too rigid — now you know the rules, you should know when you can afford to bend or break them.

Oddities

An often-surprising thing about absolute positioning is the point of reference. If you put an absolutely-positioned <div> inside another, then the position of the inside block will be relative to the position of the outside block, not the browser window. This is very useful indeed, but only if you're expecting it. Defining an absolutely-positioned block inside a statically-placed block (like this column is right now) is different - the block is lifted out of the static block and positioned relative to the <body> tag. This happens whatever unit you use, but percentages are much more obvious about it because they're a relative unit. You would probably benefit from a picture here, but I'm lazy.


You might think that (from the rules given here), there should be 25 pixels between the side panel and the main column. This is a common mistake (which is why it hasn't been corrected here): browsers in standards-compliance mode take the width of a block, then add the padding and border. This means that #menu isn't in fact 225 pixels wide, but 237 pixels, because of the 5 pixels of padding on either side and the 2 pixels (total) of black border.

If you fail to include a valid HTML 4 or XHTML doctype line at the start of your document, IE 6, Safari, Opera and Mozilla-based browsers (including Netscape 6 onward) will use a "quirks mode" in which the given width includes the padding (so the menu will be 225 pixels wide after all). There are several other differences in quirks mode, not all of them desirable (and certainly not consistent across browsers), so (IE 5 aside), it's best to use standards mode wherever possible..

The more astute of you will wonder, “What about IE 5?”
The answer is that IE 5 has no standards compliance mode; it is the quirky browser for which all these other browsers have included a quirks mode (well, that and Netscape 4). If you are designing to include IE 5 users, there are three things you can do:

Allow for differences in box size

Be flexible and leave room for IE 5's mistake. What's a few pixels between friends?

Do not specify padding on the block

Instead, put margins on all the blocks that appear inside that block by using a "descendent selector":

#menu { position: absolute;
    top: 80px; left: 25px;
    width: 225px; border: 1px solid black; }
#menu p, #menu dl { margin: 5px; }

This will put 5 pixels spacing around paragraph tags and definition lists (<dl>..</dl>)inside the menu panel (the rule doesn't apply elsewhere). Other block elements usually already have margins - particularly lists

Use a CSS hack

IE 5 has glitches in the way it reads CSS files. It's possible to exploit one of those glitches to hide a section of CSS from IE 5, while other browsers see all of the code. For example:

#menu {
    position: absolute;
    top: 80px; left: 25px; 
    border: 1px solid black; padding: 5px;
    width: 225px;
    voice-family: "\"}\"";
    voice-family: inherit;
    width: 213px;    
}

Every browser will read the width as 225 pixels, then as 213 pixels, except for IE 5, which chokes on the voice-family rule we rigged to catch it. Using CSS hacks is ugly, but is a less evil than performing browser detection. If you require a pixel-perfect layout, you may find you have no choice.