Padding Content Boxes with CSS

Posted on: September 8th, 2005 5:56 AM GMT

By: Greg Reimer (Code Monkey Extraordinaire)

Topic: CSS, web design, padding, margin

For the longest time as a CSS programmer I was frustrated by (what I thought was) CSS's inability to pad content boxes evenly. CSS of course gives you granular control of padding, but if you're like me you put all your text in <h*> <*l> and <p> elements. These block-level text containing elements (text blocks) all have built-in top and bottom margins. So, if I had code like this on my page:

/* CSS code */
div.content { padding: 10px; border:1px solid #555; }
<!-- HTML code -->
<div class="content">
<h2>Foo Bar</h2>
<p>
Blah, blah blah...
</p>
</div>

It would cause an inordinate amount of white space at the top and bottom of my block due to the 10px padding plus the margins imposed by the text blocks. For example:

Too Much Whitespace!

This is a div with 10px padding on all sides. It contains an H2 and a P element. Notice the extra whitespace at top and bottom.

The containing box pads all four sides, while the margins on the content blocks add white space between elements and also extra whitespace at the top and bottom. The image shown here illustrates what's going on with the margins and padding. For me, marginless text blocks is not an option, so my solution was to use the first-child psuedo selector to make the extra white space go away at the top:

/* CSS code */
div.content { padding: 10px; border:1px solid #555; }
div.content h2:first-child { margin-top: 0px; }

This, however, made the terrible assumption that each content block would begin with an <h2> element. I resorted to a shotgun tactic:

/* CSS code */
div.content { padding: 10px; border:1px solid #555; }
div.content h1:first-child,
div.content h2:first-child,
div.content h3:first-child,
div.content h4:first-child,
div.content h5:first-child,
div.content h6:first-child,
div.content p:first-child,
div.content ul:first-child,
div.content ol:first-child,
div.content dl:first-child { margin-top: 0px; }

This approach is riddled with holes. You're probably aware that it won't work in IE6, and it doesn't account for the extra padding at the bottom. I can write off the extra bottom padding, but the IE6 thing is too much. Another approach is to make margins exist only on the bottom of text elements:

/* CSS code */
div.content { padding: 10px; border:1px solid #555; }
div.content h1,
div.content h2,
div.content h3,
div.content h4,
div.content h5,
div.content h6,
div.content p,
div.content ul,
div.content ol,
div.content dl { margin-top: 0px; }

But this approach caused too many corner cases and oddities, and in any case how wierd is it to write this kind of CSS? So I've shifted paradigms. Given that all of my text is inside text blocks anyway, why put top and bottom padding in the box at all? And so I give you this code:

/* CSS code */
div.content { padding: 0px 10px; border:1px solid #555; }
<!-- HTML code -->
<div class="content">
<h2>Foo Bar</h2>
<p>
Blah, blah blah...
</p>
</div>

Which renders as:

Much Better

This is a div with 10px padding on the left and right, and none on the top and bottom. The margins inherent on text conaining elements takes care of that instead.

The containing box pads the left and right, while the margins on the content blocks add white space at the top, bottom and between elements. Now I have content blocks that are evenly spaced on all sides. The image shown here illustrates what's going on with the margins and the padding. It works neatly, uses minimal code, and is even forgiving if you inadvertantly slip a marginless table between elements. Do I care that this requires all text to be in block-level text elements? Not at all, because it enforces good practice. Text found outside of text blocks, in my mind anyway, is lost and in need of a home. Even images, which are semantically equivalent to text because of their alt attributes, should go into text blocks.

I should also mention that if you create boxes using a background color instead of a border, then this technique might cause you to lose your top and bottom white space, since margins overlap with no border or padding imposed between them, be they nested or neighboring boxes:

/* CSS code */
div.content { padding: 0px 10px; background: white; }

Which renders as:

This Just Looks Wrong.

This is a div with 10px padding on the left and right, but no padding on the top and bottom. Notice how CSS's margin overlapping behavior eats all the whitespace at the top and bottom. Oops!

To correct this, add 1px of padding at the top and bottom:

/* CSS code */
div.content { padding: 1px 10px; background: white; }

The 1px padding imposes itself between the two margins and prevents them from overlapping:

This Looks Right.

This is the same div with 10px padding on the left and right, and 1px padding on the top and bottom, which prevents margin overlap and gives a nice even padding around the box.

weblog home »
show all posts »