Complex Spiral Consulting

Helping clients improve the bottom line through the use of Web standards

Uncollapsing Margins

Like many basic concepts, margin collapsing can lead to unexpected and sometimes counterintuitive results. Before we explore those results and how to work around them, however, let's take a look at the most basic form of margin collapsing.

Consider a series of paragraphs that have the following style applied to them:

p {margin: 10px 0; background: #CCC;}

The separation between the outer border edges of these paragraphs will be ten pixels, as shown in Figure 1.

Figure 1. Adjacent paragraphs with collapsed margins.

Why is this? Because it's what authors would tend to expect. If you declare top and bottom margins of 1em for paragraphs, odds are that you want one em of space between successive paragraphs. If you're feeling dubious about that assertion, consider this:

p {margin: 1em 0;}
ul {margin: 1em 0;}

Closing Up Headings

A common typographical effect is to place paragraph text up close to a heading. Some people solve this by adding a class to a paragraph that immediately follows a heading, and then removing the top margin from such paragraphs. Thanks to margin collapsing, though, there's a more elegant way to solve the problem. Consider:

h1, h2, h3, h4, h5, h6 {margin-bottom: 0;}
p {margin: 0 0 1em;}

Given those rules, any paragraph that immediately follows a heading will sit right up next to it, while successive paragraphs will still be separated by a "blank line". Because margin collapsing between paragraphs causes the top and bottom margins to collapse, we can remove one of the two without changing the layout situation at all. Thus, the presence of the bottom margin on paragraphs keeps them their usual distance apart, while still allowing them to snuggle up close to headings.

The odds are very high that what the author expects, given those simple rules, is that the separation between a paragraph and a list will be one em, not two em. If more is desired, then the rules can be adjusted; for example, the margins of the ul element could be increased.

Having established all that, let's talk about a situation where margin collapsing does something that authors rarely want to see.

Marginal Excesses

The workhorse of tableless layout is the div element. Sidebars, mastheads, footers, and more all find themselves defined by an ID'ed div in such designs. Aside from its relative semantic neutrality, the div is particularly suited to this purpose because it is a flow element, which in HTML is an element that can contain both block and inline elements. In other words, you can put just about any element inside a div.

The other primary advantage of the div is that it traditionally generates a block-level box, but has no other inherent presentation. In CSS terms, a browser's built-in style sheet would assert, simply:

div {display: block;}

Astonishingly, this simple bit of style masks a potential layout problem—one that arises not because of something the author does, but more because of what the author neglects to do.

We can illustrate this problem easily enough simply by adding two elements and a small bit of style. Consider the following markup:

<div id="masthead">
<h1>ConHugeCo</h1>
<p>Making the world safe for super sizes</p>
</div>

To that very simple bit of structure, we'll apply the following very simple styles, with the result seen in Figure 2.

#masthead {background: #F80; margin: 10px;}
#masthead h1 {margin: 20px 10px;}
#masthead p {margin: 5px 10px; font-style: italic;}
Figure 2. The (barely) styled masthead.

Notice how close the content of the h1 gets to the top of the div's background area? You might expect that there would be twenty pixels of margin between the top of the h1 and the top of the div. Instead, the top margin of the h1 is actually "sticking out" of the div. The two margins actually overlap. The same is true for the bottom margin of the p element and the bottom margin of the div.

Let's illustrate this by adding dashed lines to represent the outer margin edges of the three elements.

Figure 3. The margins revealed.

In Figure 3, the margins of the div are represented by a dotted gray border, the margins of the h1 by a dotted red border, and the p element by dotted blue. As you can see, the margins of the h1 and the p overlap each other, which is normal collapsing behavior. It's the same thing that happens between successive paragraphs. You can also see that the top margin of the h1 sticks out of the masthead's content area, overlapping and exceeding the top margin of the div. A similar thing happens with the bottom of the p element.

You might well wonder why this is anything resembling a good idea. To understand it, let's take that paragraph and put it into a different set of circumstances.

Looking At Lists

The style and markup that will illustrate this point are as simple as our earlier example:

li {background: #FB8; margin: 2px;}
p {margin: 10px;}

<li>
<p>This is a paragraph in a two-paragraph list item.</p>
<p>This is also a paragraph in a two-paragraph item.</p>
</li>

For the purposes of this exercise, we'll assume the list item is part of an unordered list. List items can contain paragraphs because they, like divs, are flow elements. In fact, a list item can contain any markup that a div can contain.

Here's how the markup is rendered, with additional dotted lines to mark where the margins fall.

Figure 4. Where the margins sit.

See how the paragraph margins stick out of the top and bottom of the list item? It's the same behavior that we saw with the masthead example earlier in the article. Now notice how the first line of the first paragraph lines up nicely with the list item's marker (the filled bullet symbol). That can only happen because of margin collapsing, which is what's allowing the paragraph's top margin to stick out of the list item. Imagine that margins were prevented from doing this. If that were true, the result could very easily be what we see in Figure 5.

Figure 5. Misalignment could result without margin collapsing.

Nobody would want that to happen: it just doesn't look good. On the other hand, this is exactly what we want to have happen in the masthead: to have the margins sit inside the masthead, not collapse to the outside. So how do we keep the margins from sticking out of the masthead? There are a few ways, as it happens.

Uncollapsing

In order to "un-collapse" the margin, there are two basic solutions: padding or borders. The key is to place them appropriately. Which solution is better will depend on the design requirements for a given project.

In either case, you need to apply the padding or border to the masthead itself. Let's consider padding first. We'll add the smallest possible padding to the masthead, just one pixel on the top and bottom and none on the sides, with the result seen in Figure 6.

#masthead {background: #F80; margin: 10px; padding: 1px 0;}
#masthead h1 {margin: 20px 10px;}
#masthead p {margin: 5px 10px; font-style: italic;}
Figure 6. Masthead padding yields the desired result.

Because of the padding, the margins of the h1 and p elements do not collapse with the margins of the masthead. They are instead "contained" within the masthead's content area. This is in accordance with CSS2.1, section 8.3.1[1], but the behavior actually goes back to CSS1. Its intent, as is so often the case, is to satisfy expected authorial desires. After all, that's what drove the margin collapsing behavior illustrated by Figure 4.

Alternatively, you could kill the top margin on the h1 and the bottom margin on the p element, and create the needed space with padding on the masthead itself, like this:

#masthead {background: #F80; margin: 10px; padding: 20px 5px;}
#masthead h1 {margin: 0 10px 20px;}
#masthead p {margin: 5px 10px 0; font-style: italic;}

This would create the precise distances that were originally intended. With the one-pixel padding on the masthead shown in Figure 6, the padding "wraps around" all of the content inside the masthead. Thus there would be 21 pixels of space between the top of the h1's content area and the top of the masthead's background, not 20 pixels. If that's a real problem, then the one-pixel approach won't work. You'll have to use masthead padding and remove the margins instead, as shown in the most recent example.

Another way to keep the margins contained is to set a border on the masthead. This border can be the same color as the page background, thus making it effectively invisible. For example:

#masthead {background: #F80; margin: 10px; border: 1px solid #FFF;}
#masthead h1 {margin: 20px 10px;}
#masthead p {margin: 5px 10px; font-style: italic;}

In this case, the separation between the visible top of the masthead and the top of the h1's content area will be exactly 20 pixels, since the border sits outside that margin but blends into the page background—assuming that background is a solid color, of course. If you set the masthead's border to another color, like gray, then you'll find a distance of 20 pixels from the top of the h1's content area to the inner edge of the top border.

Summary

In the majority of cases, margin collapsing delivers the types of layout results we want. It's only in those cases where we want margins to be "contained" by other elements that things can go a bit awry. Thanks to the way CSS is written, however, there are ways to overcome the unwanted collapsing. By associating either padding or a border with an element, it will "contain" the margins of descendant elements.