No Margin for Error | November 23, 2003
Margin Collapsing
Margin collapsing is a CSS phenomenon I've been familiar with for a while. Conceptially It's very simple, however recently I've been running into a number of problems with my layouts where margin collapsing appears to be the culprit.The problems usually revolve around either extra vertical white space appearing that I just can't seem to remove or the inability to create vertical white space by using margins.
At it's core, margin collapsing is very easy to understand. Basically when two vertical margins meet up, instead of adding together, the largest margin takes precedent and the other one "collapses" to nothing.
Here is a simple example:
This paragraph has a 20px margin
So does this one
Both paragraph tags have been given a 20 pixel margin. However because the bottom margin of the first paragraph touches the top margin of the second paragraph, the margins collapse, making the space between both paragraphs 20 pixels instead of 40.
Most people think of margin collapsing happening when one block level element follows another. However margins collapse whenever one margin comes into contact with an adjacent margin. This means that margins can also collapse when one element is contained within another.
A paragraph with a 20px margin inside a div, also with a 20px margin
In the above example a paragraph (light blue) with a 20 pixel margin is wrapped inside a div (medium gray), also with a 20 pixel margin. The top and bottom margins of the paragraph tag collapse into the margins of the div tag leaving just a 20px vertical margin around both elements.
Now you've probably noticed that these two tags are contained within another div that I've applied a border to. Most people will assume i've done this just to make the examples stand out. However I've actually done this for another reason.
Here is the same example with the border on the outer div removed.
By removing the border around the outer div, the margins of the contained elements are now adjacent to the margin of the preceding element (in this case a paragraph tag) and have all collapsed together. Now while this is what margin collapsing is supposed to do, if you don't know what's going on here, this kind of thing can be a bit of a head scratcher.
There are number of ways to get round margin collapsing issues. One way is to add a border or 1px of padding around the elements so that the borders are no longer touching and so no longer collapse.
The same example but this time each element has been given a border
Another way to stop margins collapsing is to change the position property of the element.The CSS2 Specs explain that margins of absolutely and relatively positioned boxes don't collapse. Also if you float a box it's margins no longer collapse. It's not always appropriate to change the position properties of an element but in some situations if you're having problems with unwanted margin collapsing, this may be an option.
Before I move on, it's probably worth bringing up self collapsing boxes. A self collapsing box is one where it's top and bottom margins meet.
Here is a very simple example of a self collapsing block
This paragraph has a 20px margin. After this paragraph is another, empty paragraph, also with a 20px margin
Because the second paragraph has no content, it's margins collapse together and they in turn collapse with the preceding paragraph. This is why you can put loads of empty paragraph tags in a page yet they take up no space. Usually this won't cause any problems, however people occasionally use empty elements to clear a float for instance, so this behavior needs to be born in mind.
Cleared Elements
On the subject of margins and floats, here is an interesting situation I came across a few days ago while trying to lay out a page.
In the above example it would be reasonable to expect that the div with the 20px margin would be 20 pixels below the floated div. However in actual fact it appears to be only a couple of pixels below the floated div.
If you look at the CSS2 Specs for clearing floats you'll get a better understanding of what's going on. When you clear something, what actually happens is the element you've applied the clear to increases it's margin enough so that it clears the proceeding floated boxes. If that element already has a margin the largest margin wins. In this instance the 20px margin is just slightly larger than the height of the floated box and it's top starts at the top of the floated div. Because the floated div is slightly less than 20px tall you get a small gap between the two elements background colours.
In a layout I was working on recently I ended up with both these phenomenon happening at once. Things were collapsing all over the place (literally and figuratively). I even ended up having problems with an empty div I was using to clear a float apparently collapsing in on it's self and then collapsing with other elements, causing all sorts of layout problems. So if you find yourself in a situation where you are using margins to space out elements but are getting unpredictable results, it may be down to margin collapsing, it may be down to cleared elements and if you're really unlucky it may be down to both.
Posted at November 23, 2003 10:24 PM
Eric TF Bat said on November 23, 2003 11:21 PM
In IE6/Win, the last example does, indeed, have the margin you expected. In Moz 1.5/Win it doesn’t, in keeping with the spec. I’m seeing more and more that it’s essential to start one’s testing in the most compliant browser available, ie the latest version of Mozilla. After that, you test with the most popular browsers, ie IE5+/Win. If one must produce workarounds for browser bugs, it’s a better thing to start with correct code and selectively add the least possible hackery, rather than to start with a mess of hacks and twiddles and then have to figure out which ones you can safely remove!