The concept of collapsing margins is very simple but to fully understanding its behaviors in CSS can be tough at first. When 2 or more vertical margins hit each other, they are combined (collapsed) to form just one margin. The largest of the margins is the one rendered in the flow. The formula in theory then, for the bottom or top margin of the adjoining boxes will be:
margin-top | margin-bottom: max(
margin-box-1 ... margin-box-n
);
When it comes to the real world there are 3 major categories of margin collapsing. So let’s figure out how these 3 types of collapsing work and how to tame them.
1) Adjoining boxes of sibling elements
The bottom margin of an in-flow block-level element is always adjoining to the top margin of its next in-flow block-level sibling, unless that sibling has clearance.
<div>
<div>content</div>
<div>content</div>
</div>
While margin collapsing is great for written text such as paragraphs and headings etc., it can get somewhat tricky if you’re trying to get pixel perfect spacing between your boxes, so there might come a time when you want to disable margin collapsing. Take a look at these examples that suggest ways of uncollapsing your margins.
So it seems the only way to break out of collapsing that works in both IE and FF is our second example by using floats and clear combined. You might have noticed the above 4 boxes themselves also have 20px margins which have collapsed to form 20px margins within our 3 adjoining sections in the middle.
2) Adjoining boxes of ancestor elements
The top or bottom margins of contained elements will always collapse together to form one margin. If the element’s margins are collapsed with its parent’s top margin, the top border edge of the box is defined to be the same as the parent’s. Below is the sample HTML and diagram and explanation of how to avoid this.
<div>
<div>content</div>
</div>
Remember that collapsing only happens if the margins actually touch one another. In this case the inner box’s margin ends where the outer box’s margin starts, therefore they are touching. One easy way to avoid this type of margin collapsing is to add either vertical borders or vertical padding to the parent box. Take a look at these examples:
You might be wondering, so why does the margin stick out of the outer div instead of being applied to inner div? Remember that the height of containers are calculated based on the the height if their children, and a block level element's height is measured from its top border edge to its bottom border edge. So the outer div only honors the content height of its children when calculating its own height, and since margins are already collapsed, the inner margins will appear to protrude out of the parent.
3) Self collapsing boxes
Empty block level elements result in a special case of margin collapsing. Their top and bottom margins actually touch each other and they basically self destruct based on the rules of margin collapsing. According to the W3C: An element’s own margins are adjoining if the ‘min-height’ property is zero, and it has neither top or bottom borders nor top or bottom padding, and it has a ‘height’ of either 0 or ‘auto’, and it does not contain a line box, and all of its in-flow children’s margins (if any) are adjoining.
<div>
<div>content</div>
<div></div>
<div>content</div>
</div>
Another obvious way to break out of collapsing is changing the display to absolute. Finally, note that the margins of the root element box in any document never collapse. There are a few rules for negative margins when it comes to collapsing. I will try to write another post on this later.
I’ve created a demo page here with the above examples.
References and Acknowledgments
- W3C Box Model Collapsing Margins
- Andy Budd No margin for error
- Research Kitchen CSS Autoheight and Margin Collapsing * Complex Spiral Uncollapsing-margins
- La Chatte Noire tests: block formatting context, display:inline-block and margin collapsing