Skip to main content

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-top and margin-bottom collapse. 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: hidden each disable collapsing.
  • Normal flow only. Absolutely positioned and floated elements do not collapse.

Quick example

css
.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.

html
<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-top or padding-bottom
  • border (even 1px solid transparent)
  • overflow: hidden or overflow: auto
  • display: flow-root (cleanest option, no side effects)
  • display: flex or display: 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

html
<article class="post">...</article> <article class="post">...</article>
css
.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

css
.hero { background: #f0f0f0; /* No padding or border */ } .hero h1 { margin-top: 48px; }
html
<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 ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?