Thought you should know...

We ran into a problem that people sometimes see when working with CSS on their web pages, and I wanted to discuss it, showing you examples of the behavior so you can see what's going on. The problem is usually referred to as the "collapsing margins" problem. It has to do with the way CSS handles top and bottom margins of "items" in a web page whose margins "touch".

We saw the problem while putting together some content for our slideshow feature box which you can see above. I'm going to show you examples of the behavior and how to "fix" it with a "scaled down" version of one of the slides. The thin blue border in these examples represents the feature box at the top of our site that holds the slideshow. We're using the same background image to show you the content of the slide, and the red box is the text.

Our objective: have the "curtain" filling the content area, and the "Thought You Should Know" text both vertically and horizontally centered on the curtain. This turns out to be a little trickier than expected, because of the collapsing margins problem.

First, let's look at our first attempt where we made a boneheaded mistake, and see what it looks like.

This is what it looks like:

Introducing Thought You Should Know

OK, so the curtain fills up the blue-bordered content area, but the text didn't get centered at all. What's the problem?

The problem is that the span tag is an inline element, meaning an element that appears inline in text content. It is not a block-level element, which is the type of element that has a defined area, with padding, borders and margin that can be controlled. So, naturally, our attempt to set margins on it failed miserably.

OK, fine. So we'll nest the span tag inside a div element so that we'll have a containing block that we can set margins on to center it inside the curtain area.

So, let's look at our second attempt and see the weird behavior that had us scratching our heads.

And here is what it looks like:

Introducing Thought You Should Know

So great. That's not what we want either. We've got the containing div with the blue border, and it's set to be 200 pixels tall. Then we put the 200 pixel tall div with the curtain background inside it. What we would expect is for the curtain to completely fill the blue div, and then whatever we put inside the "curtain" div to be positioned inside it. Instead, it's like the top margin we put on the content is being applied to the curtain div relative to its parent instead. What's going on?

This is one of the incarnations of the collapsing margin. Collapsing margins occur when two or more block-level elements appear on the page and their top or bottom margins line up exactly. When this happens, their margins are not added together; the largest of the margins gets applied to all the elements instead. The behavior is meant to prevent elements stacked on top of each other from ending up with more whitespace between them than would normally be expected, but it can have some unexpected side effects like what we see here.

Usually the collapsing margin affects "sibling" elements, but it can also affect nested parent-child elements like this. How do we prevent the problem? By understanding when margins collapse. Margins collapse when they "touch". Margins "touch" when there is no padding, border, or content between them. In this case, the child div is directly inside the parent div with nothing in between. And that gives you a clue as to how to solve the problem. They need something "between" them, whether it is content, or padding, or a border. Let's put the simplest content you can think of between them. We will add a single letter, the letter "X" between them. Watch what happens:

And here is what it looks like:

X
Introducing Thought You Should Know

See how the behavior changes? And it may be a little hard to see, but the X appears at the top left corner of the parent "curtain" div. You can see it better by clicking and dragging across it to highlight it. Obviously, we don't want to have a letter X sitting there like that, but this proves that the problem is caused by a collapsing margin.

We can now solve the problem in a way that looks "right", by adding a 1-pixel padding to the parent "curtain" div. That adds a pixel of space between its top margin and the top margin of the nested div, and the margins won't collapse. While we're at it, we remove the red border on the nested div so we can see the final result.

And here is what it looks like:

Introducing Thought You Should Know

And that is the display we were really after. Hope this helps our readers who might run into this problem!

Read more posts tagged with:

More posts filed under category: Tips and Tricks

Like this post? Subscribe to our RSS feed and get loads more!