What is margin collapsing in CSS
Margin collapsing is a CSS behavior where two vertical margins meet and only the larger one takes effect, not their combined total.
Theory
TL;DR
- Only
margin-topandmargin-bottomcollapse. Horizontal margins never do. - Three scenarios cause it: adjacent block siblings, parent and first/last child, and empty elements.
- The larger margin wins. Equal margins produce one margin of that size.
- Flexbox, Grid, and
overflow: hiddeneach disable collapsing. - Normal flow only. Absolutely positioned and floated elements do not collapse.
Quick example
.card-top {
margin-bottom: 40px;
}
.card-bottom {
margin-top: 24px;
}
/* Actual gap between them: 40px, not 64px */The browser picks the larger value. The 24px disappears.
The three scenarios
Adjacent siblings is the most common case. When margin-bottom of one block meets margin-top of the next, they collapse into one. This is what catches most developers the first time they try to space out a list of cards or article previews.
Parent and first/last child is trickier. If a parent has no padding-top, no border-top, and no inline content before its first child, the child's margin-top collapses with the parent's margin-top. The margin escapes out of the parent. Same logic applies at the bottom.
<section> <!-- no padding, no border -->
<p style="margin-top: 32px;">First paragraph</p>
</section>The section itself shifts down 32px. The paragraph does not move relative to the section.
Empty blocks collapse their own top and bottom margins into one. Rarely a real issue in modern code, but it explains strange spacing in legacy markup.
How to prevent collapsing
For the parent-child scenario, any of these on the parent element works:
padding-toporpadding-bottomborder(even1px solid transparent)overflow: hiddenoroverflow: autodisplay: flow-root(cleanest option, no side effects)display: flexordisplay: grid
For sibling collapsing, the fix lives at the container level. Switch the wrapper to display: flex with a gap, and margins stop collapsing entirely.
Common mistakes
The most common one: a developer adds margin-top: 40px to a heading inside a section, then wonders why the entire section shifts down instead of the heading. That is the parent-child collapse. One line fixes it: display: flow-root on the parent.
Another frequent surprise: two components each have margin-bottom: 30px and margin-top: 30px. The developer expects 60px of space, gets 30px. Nothing is broken. Collapsing is working as specified. I have seen this cause a long debugging session during a design handoff where spacing matched Figma but the developer expected additive margins.
Negative margins follow their own rule. If one margin is -20px and the other is 30px, the result is 10px (they add together when signs differ). Two negative margins produce the most negative one.
Follow-up questions
Q: Does margin collapsing happen inside a flex or grid container?
A: No. Both create a block formatting context, which disables collapsing for all direct children.
Q: What happens when one margin is negative?
A: Negative and positive margins add together. So 30px and -10px gives 20px. Two negatives produce the most negative value.
Q: Is display: flow-root better than overflow: hidden for this?
A: For this specific problem, yes. overflow: hidden clips content that extends outside the parent, which is usually an unwanted side effect. display: flow-root creates a formatting context without clipping anything.
Q: Can horizontal margins collapse?
A: No. The CSS spec only defines collapsing for vertical margins in normal flow.
Examples
Sibling spacing that does not add up
<article class="post">...</article>
<article class="post">...</article>.post {
margin-top: 32px;
margin-bottom: 32px;
}
/* Gap between two posts: 32px, not 64px */Each post declares 32px on both sides, but between any two posts there is only 32px total. For predictable spacing in card layouts, use gap on a flex or grid container instead of margins on the items.
The parent-child margin escape
.hero {
background: #f0f0f0;
/* No padding or border */
}
.hero h1 {
margin-top: 48px;
}<section class="hero">
<h1>Welcome</h1>
</section>The h1 margin collapses with the section's top margin. The whole section moves down 48px, not just the heading. Adding padding-top: 1px to .hero or setting display: flow-root keeps the margin contained inside.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.