A good portion of this comes from the CSS box model. As defined by the W3C, a block's width is defined as being its declared width, PLUS its border, PLUS its padding. Thus a 300px-wide DIV with a 1px-wide border and 10px of internal padding will end up taking 322 pixels worth of space on a page.
Some browsers from a small company in Washington, however, defined a block as being the declared width. Period. Any defined padding or borders are contained within the box, thus a 300px-wide DIV with a 1px-wide border and 10px of internal padding will end up being... stay with me here... 300px wide.
Personally, this is one of those instances where I think the boys from Redmond made the right call. In the real world if I tell someone to make me a box 12" on a side I'll end up with a box a foot square, and that takes up a square foot on the shelf. Tell them to add an inch of foam padding to the inside, and that box is still a foot square, and still takes up a square foot on the shelf.
Plus with the "standard" I end up having to do the math, as I did in the first example above. Change my mind and decide the box will look better with 13px of padding, and I need to change the column width to 300-13-13-1-1, or 272, in order to maintain a box size of 300px.
At any rate, this small difference in rendering blocks has generated an enormous amount of trouble. Both in simply explaining the problem, and in trying to fix it. The usual solution is the infamous "box-model hack", which replies on errors in the browser's CSS parser in order to feed it two different values, first the "right" one (grin), then the "standard" one.
Which means that I still need to do the calculations, AND to define every boxes' size twice. This is progress?
.column {
width:300px;
padding:13px;
voice-family: "\"}\"";
voice-family:inherit;
width:273px;
}
There had to be a better way.
So I did some experimentation, and found it. My new rule was simple: Never define a boxes' width AND padding in the same element.
Here's an example:
<div class="column"> <div class="border"> <div class="block"> Here's a content block. </div> <div class="block"> Here's another one. </div> </div> </div>
And the associated CSS:
.column { width:300px; }
.column .border { border:1px solid black; }
.column .block { padding:13px; background:#fff; }
Giving a perfectly rendered 300px-wide box in nearly any semi-modern browser:
I nest three divs, the first, the enclosing column, has a width of 300px. Next is the border, if any, while each internal block of content contains the padding of 13px. (Better, perhaps to use margin to avoid the extra space between blocks.)
But Michael, you protest. You've just substituted more markup for less CSS. Which is true. And not true. Because the extra markup let's you do things you couldn't do before. As in:
.column .block { padding-bottom:5px; border-bottom:1px solid silver; }
Now each content block in the column ends with a divider line. Or each block could be shaded. Or each additonal DIV could be shifted or positioned or have its own background. Or whatever.
The point is that having just a bit more markup than the minimum gives us flexibility in our design, much as in objected-oriented development we add methods to give derived classes places to "hook" into the system.
Note that even the holy grail of CSS sites, CSS zen Garden, advocates this approach, often adding a extra DIV here and SPAN there in order to give designers the CSS hooks needed to completely customize a site. Without that "extra" markup, many of the redesigns simply would not have been possible without changing the source HTML.
Go with the "bare bones" approach commonly advocated, and you'll probably find that making a major change in the site's appearance will require changing each page as well. Plan for the future with a little extra markup, however, and it may well be, like zen Garden, that just few small CSS changes will get you where you need to be.
Does every box on your site need this triple-treatment? Obviously not. But I highly recommend it for major content containers, sidebars, and similar page structures.
So in one blow we've created CSS-standard compliant markup, eliminated problematic browser hacks, and ended up with a much more flexible design to boot. Is this a great country or what?
This is a perfect example of how broken standard css is. Of course, these days I only do positioning via standard css using xhtml transitional, but the fact remains that it requires a lot of markup in the html to get any flexibility to accomodate future design changes.
Posted by: nerpi | February 20, 2009 at 10:56 AM
I tended to think of it as defining 'width' and 'margin' on the outer block,
and 'border' and 'padding' on the inner block, but to "Never define a boxes' width AND padding in the same element" is much more concise. Thanks!
Posted by: Steve | June 12, 2009 at 12:10 PM
Wait! The broken box model includes the border as well as the padding, so the rule is:
Never define width with border & padding,
Or:
Outer block: margin & width
Inner block: border & padding
So you didn't really help me after all!
Posted by: Steve | June 12, 2009 at 12:29 PM