OK, so some spacing walks into a bar, trips and falls on the floor. The bartender asks if he should be cut off and the spacing replies, “No, I’m just a collapsed margin.”
Sorry, dumb joke.
On a more serious note, collapsing margins are real and they can be a real pain in the neck if you’re not aware of what they are and how they behave. Here are a couple of scenarios where we’d see these little buggers come into play.
When Vertical Worlds Collide
Collapsing margins happen when two vertical margins come in contact with one another. If one margin is greater than the other, then that margin overrides the other, leaving one margin.
Let’s say we had elements stacked on top of each other, one with a bottom margin and one with a top margin:
.module {
display: block;
width: 100%;
height: 150px;
}
.module__top {
margin-bottom: 25px;
background-color: #f38a6d;
}
.module__bottom {
margin-top: 50px;
background-color: #3bbfef;
}
If the modules above are placed next each other in the HTML markup, then we might expect there to be 75px
(25px
from the top module plus 50px
from the bottom module) between them vertically, right?
Well, in this edition of CSS Survival of the Fittest, we only get 50 of those pixels. It’s like the bigger margin straight up ate the other one and left nothing behind.
See the Pen Collapsing Margins: Vertical by CSS-Tricks (@css-tricks) on CodePen.
Go ahead and measure. The space between those two modules amounts to the 50px of the module__bottom
and kicks the margin from module__top
to the curb.
A natural reaction might be to keep increasing the smaller margin until it makes a difference. But alas, when both margins are positive numbers:
bigger margin = total vertical margin
Those of you more mathematically minded than the likes of myself may cleverly ask: what about negative margins? The answer is that it does have a significant impact and reduces the margin between the two elements.
50px + (-25px) = 25px
In English, if one margin is negative, the negative margin is subtracted from the positive margin, reducing the total vertical margin. Here’s what that looks like:
See the Pen Collapsing Margins: Vertical and Negative by CSS-Tricks (@css-tricks) on CodePen.
And if both margins are negative? The same rule holds as if both were positive. However, the margin that collapses is the bigger negative of the two rather than the one that is closest to being positive. For example, if one margin is -25px
and the other is -50px
, then -50px
will be the margin.
Another situation you might wonder about is when one vertical margin meets an equal vertical margin. If this were truly “survival of the fittest”, then two clashing equal margins should either live together or die together, right? That’s a good thought, but what ends up happening is that one continues to get used and one is collapsed. It’s sort of like one swallowed the other, though we’re not sure which one gets swallowed.
When Parents Ground Their Children
Collapsing margins also occur when the margin of a child element crosses the margin of its parent. Let’s consider the following:
/* Parent */
div {
margin: 15px;
}
/* Here come the children */
.red {
background-color: #ff6b6b;
}
.orange {
background-color: #ff9e2c;
}
.yellow {
background-color: #eeee78;
}
.green {
background-color: #4ecd9d;
}
.blue {
background-color: #4e97cd;
}
.purple {
background-color: #6c4ecd;
}
In this example, div
is the parent and each class after is a nested child element. That establishes the parent-child relationship.
Again, our natural inclination might be to expect the total margin to be the sum of the parent and child margins. That’s not the case, however, and the child margin will be overridden by the parent margin – at least as long as the child element lives under the parent element’s roof. Parents can be so bossy.
But like any parental punishment, there is a way around this by adding something solid to the parent. In this case, adding 1px
of padding allows both margins to be used.
See the Pen Collapsing Margins: Parents and Children Comparison by CSS-Tricks (@css-tricks) on CodePen.
The same would be true if we added border-top
to the parent. As long as something solid sits between the parent and child, both margins will be used.
In Conclusion
Do you see how collapsing margins can make things tricky? I personally encounter this on a frustratingly frequent basis when dealing with typography. I’m tempted to add margins to things like <h1>
and <h2>
but that often ends up being the source of a lot of headache down the road as vertical margins collide with one another.
I’m interested to know what you all think about collapsing margins. In particular, how do you manage them in a pattern-based system? Harry Roberts offers some nice tips of his own. Please share!
This is why, generally, I only apply margin-top to elements.
Same here. Top margins, especially in typography, started as a good practice and became the defacto standard for kodmunki! Its an excellent “pattern” that has saved countless dev hours and spared many a designer from nose-flattening, eye-blackening, slamming of face into keyboard! :{)}
Good article, useful clear information. Having been frustrated more than once by collapsing margin :-)
Using a clearfix between the colliding elements also solves this.
I go with Harry Roberts technique of only using margin bottom. It takes some getting used to, but it’s so worth it.
As a bonus, the typographic rhythm of my projects is noticeably more consistent and far easier to manage.
I’m following Harry’s rule since he published his article and have avoided any hassle with collapsing margins so far. If I however encountered collapsing margins in projects I got introduced to(some code already written), it was a good reminder of why I’m avoiding bidirectional margins.
Something I’ve always wondered is why margin collapsing occurs – are there circumstances where it’s useful?
The margin collapsing comes from graphic design.
There, you have margins to title and subtitles, but when a subtitle comes just after the title you should not double the margins. This is why they developed the concept of collapsed margins and this is why it happnes just on vertical margins.
When margins were introduced to web design, websites were just white pages with formated text in it. So, margins were used basically for text or images inside the text. Basically all elements were display:inline, so the collapsed margins were the way to go and became the norm.
Because typographically (for example) they make a lot more sense. Are there any circumstances where it’s not useful? ;)
I thing it is worth mention that overflow hidden also prevents margin collapsing –> http://codepen.io/anon/pen/wazRXY
If I remember correctly that is the reason why micro clearfix also has a before pseudo element. Otherweise overflow hidden and clearfix would yield different results.
I always push my self to avoid to use margin-top css property. Only use margin left, right, and bottom for full 100% width. But if there some tags at the horizontal line, I use tag+tag and write left or right margin only.
For the empty parents and childs without any content I always use properties like display block with specific height and width.
If we consistent with this, we should get any space as expected.
Oh once more. If I use pseudo elements like ::before anda ::after to make any decoration like empty space with color, I add one more property that use to give “empty one space” content to the pseudo elements like content:” “;
As others have said, I only use
margin-bottom
and make exceptions only when absolutely necessary. If necessary, this situation can be handled with some styles specifically for sibling behavior. Thankfully, we have the sibling selector+
to let us do that.Great post! Cleared all my doubts about margin collapsing, especially in case where we’ve one positive and the other negative margin.
Here are cleaner ways to avoid collapsing margins (no 1px padding or border tricks):
Yep,display:inline-block it is a good alternative.
For those situations where you can’t use width 100% (old IE and right/left padding/border/margin) you can use this trick:
Uses before and after pseudo elements given height and negative margins to force parent padding without affecting the size of the original content.
Comes with its own drawbacks, of course, in that you need to be able to use before and after pseudo elements which may already be needed for other purposes.
Working codepen (the other was created anonymously):
{ float: left; width: 100% }
also applies both margins, although this approach is not very cool because of the float…I’ve been using only margin-bottom for years now and it works great. I try to make my sites as modular as possible, so having only margin-bottom makes it so I don’t have to worry about how different combinations of modules fit together. If I ever have any unique margin needs, I tend to use ‘adjacent sibling’ (
.this + .that
) or:last-child
selectors to fix those specific instances.I use margin-top on elements that proceed other elements: http://alistapart.com/article/axiomatic-css-and-lobotomized-owls.
Ehm… absolutely not. Math gives us a very specific meaning of the funtion
max(x,y)
. Ifx==y
thenmax(x,y)==x==y
. It doesn’t make any sense to think thatmax(x,y)
would be 0 orx+y
.While I can see some (easily solved) problems with containers and the like, how would you create properly spaced paragraphs and headings without collapsing margins?
I usually use display: inline-block, float: left, and clear: both…
Two germophobic women are standing next to each other on a subway platform. Both demand to have a 12-inch “bubble” of separation from the other. Both women are satisfied they have maintained their perceived “bubble”, but there is still only 12 inches (not 24) between them.
I don’t really struggle with this concept as I’ve always seen margin as, “give me at least this much breathing room from any outside element.” If you, however, want that bubble to be “mine, all mine” then use padding. Padding is more like “I don’t want to touch anything, neither outside elements nor even the side of my own container.” Margins seem to be made perfectly for collapsing, (oh, and for that nice horizontal centering, ala
margin: x auto;
).Word! Strangely enough, in CSS world the space between that women would still be 24 inches, as long as they stand NEXT to each other (on the horizontal axis). It only collapsed to 12 inches, if one woman would float above the other one.
Thanks for sharing this post, I am new in website design and development. Your article will help me in designing my upcoming website.
I’m trying to put together a general purpose stylesheet.
I think I like the idea of almost all elements having a top margin of 0px and using bottom margin to control vertical spacing. I’ve certainly run into many cases where setting top margin on things gives me headaches.
Problem 1: I want P’s to have 1.5em bottom margin in general, but if a P is above another P, I want its bottom margin to be a bit less, like 1em. In other words, a clump of Ps together would have less of a gap between each one than there would be above and below the whole clump of Ps. This would be easy if we had a selector that would act on the front sibling of something like this:
p+p
. But we know that only selects the last P in the statement.Problem 2: Similarly, I’d like to let Ps (and several other block elements, like UL, Table, etc) have a bottom margin of 1.5em unless they are followed by an H1-6 tag, in which case I want 1.8em. Again, a selector that would act on the first element in the statement (e.g. p+H1) would be what I need.
So…
Anyone know how to select a P only if it is followed by a H1?
Or a P that is followed by another P?
Ideas
If there’s just not a selector to do the job naturally…
What might address both problems is creating a class (maybe named “needExtraSpacingBecauseImTheLastOne”) to have more margin to give to any element that will preceed an H1, or other header tag.
For Problem 2, I could put a top margin on the headers, but create a class that I could put on any one of them to zero out the top margin (like if it were the first heading in a block/page, and I didn’t want the extra top gap).
Or simply use
p+h1
and increase the top margin, since what you want is to target paragraphs followed by headers (or headers following paragraphs, it’s the same). Way simpler and avoids unnecessary classes.Thanks for replying, Lazza.
However, P is not the only tag I would need to put in that kind of sibling notation. I’d have to add blockquote+h1, form+h1, ul+h1, and a several others. So if you take the maybe 9 block-level tags and iterate through all 6 H tags, you end up with 54 statements you have to have, as opposed to six H.noMarginAbove -type classes. That makes the classes worth some consideration.
However, your idea might be right for my sitation. I’ll sure look at it. Thanks!