Problem Solved

CSS · margin collapse

Home › Courses › CSS › Problems › Margin collapse
🎨 Concept · 3 min read

Why is my spacing wrong?
Margin collapse.

You set margin-bottom: 20px on the first paragraph and margin-top: 20px on the second. You expect 40px of space. You get 20px. Or — worse — you put a child inside a parent with margin-top: 20px and the whole parent moves down. That's margin collapse, and it surprises everyone the first time. This page covers the three cases and the four fixes.

Short answer: Adjacent vertical margins collapse into one — the larger margin wins. Two 20px margins become 20px, not 40px. It happens in three cases: adjacent siblings, parent and first/last child, and empty elements. It applies only to vertical margins in normal flow — not horizontal margins, not flex/grid items. Fix with padding on the parent, overflow: hidden, or better — use gap in flexbox/grid instead of margin for spacing.

✅ The three cases

When margins touch, they collapse.

Adjacent siblings

<p>A</p><p>B</p> — A's margin-bottom and B's margin-top collapse to the larger one.

Parent and first child

Parent has no padding, border, or overflow. The child's margin-top collapses with the parent's, pulling the whole parent down.

Empty element

A <div> with no content collapses its own top and bottom margins into one.

Only vertical, only flow

Horizontal margins never collapse. Flex and grid items never collapse. Inline elements never collapse.

✅ Case 1 — Adjacent siblings

Two paragraphs, one gap.

adjacent.css
.para-a {
  margin-bottom: 20px;
}

.para-b {
  margin-top: 20px;
}

/* The visual gap between A and B is 20px,
not 40px. The margins collapse to the
larger of the two. */
Visual result:
┌────────────────────┐
│    Paragraph A     │
└────────────────────┘
       ↕ 20px (not 40px)
┌────────────────────┐
│    Paragraph B     │
└────────────────────┘

Why? Because margin-bottom: 20px and
margin-top: 20px are adjacent. The browser
merges them into one 20px margin.

If A had margin-bottom: 40px and B had
margin-top: 20px, the gap would be 40px
(the larger of the two).

This is intentional — it keeps spacing
consistent in flowing text. If you wanted
40px, use padding: 20px on the parent, or
use flexbox with gap.

✅ Same result: 20px, not 40px.
✅ Predictable — you just have to know the rule.

✅ Case 2 — Parent and first child

The margin leak that surprises everyone.

parent-child.css
.parent {
  background: lightgray;
}

.child {
  margin-top: 20px;
  background: white;
  padding: 10px;
}

/* The parent has no padding, border, or overflow.
The child's margin-top collapses with the
parent's margin-top — both are now 20px
above the parent. The parent appears to
be pushed down by 20px, even though the
margin was set on the child. */
Visual result (BAD):

↕ 20px ← the parent's top has moved
┌────────────────────┐
│ ┌────────────────┐ │
│ │     Child      │ │
│ └────────────────┘ │
└────────────────────┘

The parent's top edge has collapsed into
the child's margin. The child's margin-top
"leaked out" of the parent.

Fix: add padding, border, or overflow
to the parent — that creates a boundary
that prevents collapse.

.parent { padding: 1px; } /* fix 1 */
.parent { border: 1px solid transparent; } /* fix 2 */
.parent { overflow: hidden; } /* fix 3 */
.parent { display: flex; } /* fix 4 */

After the fix, the child's margin stays
inside the parent. The parent's top is
where you expected it.

✅ The modern fix — gap

Stop fighting margin collapse. Use gap.

gap.css
/* ❌ The old way — margin collapse
makes this unpredictable */
.stack > * + * {
  margin-top: 1rem;
}

/* ✅ The modern way — gap
between items, no collapse */
.stack {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Or with grid */
.stack-grid {
  display: grid;
  gap: 1rem;
}

/* Same visual result, no collapse tricks. */
gap: 1rem in flexbox or grid:

✅ Consistent 1rem between every pair of items.
✅ No margin collapse — the items are flex/grid
children, and margins don't collapse between
them.
✅ No first-child or last-child edge cases.
✅ No parent-child leak.
✅ Works with unknown number of items.
✅ Same API in flexbox and grid.

This is the fix. Use gap for spacing between
siblings. Use padding for spacing inside a
container. Use margin only for spacing
between unrelated elements (e.g., a paragraph
and an image in flowing text) — where the
collapse is actually what you want.

Modern CSS layout is gap-based, not margin-based.

Don't add overflow: hidden to a parent just to stop margin collapse. It works — overflow creates a block formatting context, which prevents the collapse. But it also breaks position: sticky on any descendant, clips box-shadow and dropdown menus that extend past the edges, and hides absolutely positioned children that overflow. Use padding on the parent or display: flow-root instead — they create the same containment without the side effects. Better yet, use gap in a flex/grid container and skip the whole problem.

⚠️ Common mistakes

The margin-collapse mistakes that cost real time.

1. Expecting 40px from two 20px margins

They collapse to 20px. Fix: use padding, or gap.

2. Child's margin leaking out of the parent

Parent has no padding/border/overflow. Fix: add padding or display: flow-root.

3. Adding overflow: hidden to "fix" it

Breaks sticky, clips shadows, hides dropdowns. Fix: padding or flow-root.

4. Using margin: 0 everywhere

Removes the collapse but also removes spacing. Fix: use gap or padding explicitly.

5. Negative margin collapse

Negative margins collapse differently — the more negative wins. Fix: avoid negative margins for layout.

6. Padding on the wrong element

Adding padding to the child doesn't stop the collapse. Fix: padding on the parent.

7. Empty div margins

Collapse internally. Fix: give empty divs a purpose (role, content) or use CSS for spacing.

8. Expecting flexbox to collapse

Flex items never collapse. Fix: use gap for consistent spacing.

❓ Frequently asked

What is margin collapse in CSS?

When two vertical margins meet, they collapse into a single margin equal to the larger of the two. Two divs with margin-bottom: 20px and margin-top: 20px have 20px of space between them, not 40px. This is a spec behavior, not a bug — it's designed to prevent double spacing in articles. Margin collapse only applies to vertical margins in normal flow. It doesn't apply to horizontal margins, padding, borders, or flex/grid items.

When does margin collapse happen?

Three cases. (1) Adjacent siblings — two block elements one after the other in the same parent. (2) Parent and first/last child — if the parent has no padding, border, or overflow, the child's margin collapses with the parent's. (3) Empty elements — a block element with no content collapses its own top and bottom margins into one. All three happen only with vertical margins in normal flow.

How do I stop margin collapse?

Four fixes. (1) Add padding or border to the parent. (2) Add overflow: hidden (or auto, or scroll) to the parent — but this breaks sticky and clips content. (3) Use flexbox or grid — margins don't collapse between flex/grid items. (4) Use gap instead of margin for spacing inside a flex/grid container. In modern CSS, gap is the preferred fix.

Does margin collapse happen in flexbox or grid?

No. Margins do not collapse between flex items or grid items. Each item's margin applies independently — two flex items with 20px margins have 40px of space between them, not 20px. This is one reason flexbox and grid are preferred for component-level spacing: the spacing is predictable and additive, unlike normal flow. However, the flex container itself still follows normal margin rules.

Why does margin collapse make my parent margin look wrong?

Because the child's margin collapses with the parent's. If a parent has no padding or border, its first child's margin-top collapses with the parent's margin-top. The child pulls the parent down with it. Fix: add padding or border to the parent, or set overflow: hidden, or use display: flow-root, or make it a flex container.

Should I use padding or margin for spacing?

Padding inside an element; margin between elements. But in modern CSS, use gap for spacing between siblings — it's what margin collapse is trying to solve, done right. gap: 1rem on a flex container gives 1rem between each pair of items, no collapse, no hacks. For vertical rhythm in articles, use margin-bottom on paragraphs — the collapse between paragraphs is intentional and gives you even spacing.

🔗 Related

← All CSS problems
Problem solved · CSS