Formatting contexts and margin collapsing

CSS · Expert · 14 min

Strange gaps, escaped margins and collapsed parents all follow from formatting-context rules.

Layout in CSS is organised into formatting contexts: regions where boxes are laid out by one set of rules.

A block formatting context (BFC) stacks block boxes vertically. Inside one, vertical margins of adjacent blocks collapse: the gap is the larger of the two margins (or the sum of the largest positive and most negative). Collapse also happens between a parent and its first or last child when nothing separates them (no border, padding, inline content or height). That's why a child's margin-top can appear outside its parent, pushing the parent down.

A new BFC is created by the root, floats, absolutely positioned elements, inline-blocks, table cells, overflow other than visible/clip, flex and grid items, and explicitly by `display: flow-root`. Margins never collapse across a BFC boundary, and a BFC contains its floats: the classic fix for a parent with zero height because all children float is display: flow-root.

An inline formatting context lays out text and inline boxes in line boxes. Each line's height comes from line-height and the tallest inline content aligned by vertical-align. Images are inline by default and sit on the text baseline, leaving a small gap underneath for descenders; display: block or vertical-align: middle removes it.

Flex and grid containers establish their own flex/grid formatting contexts, where margins never collapse and floats don't apply. This is one reason spacing with gap in flex or grid is more predictable than stacking margins.

Example

/* <section class="box"><h2>Title</h2></section> */
.box { background: #eef; }
.box h2 { margin-top: 2rem; }   /* margin escapes: gap appears ABOVE .box */

.box { display: flow-root; }    /* new BFC: margin stays inside the box */

/* parent of floats collapsing to zero height */
.media { display: flow-root; }  /* contains the float */
.media img { float: left; margin-right: 1rem; }

/* gap below inline images (baseline alignment) */
.thumb img { display: block; }

/* margins collapse: 24px apart, not 40px */
p.a { margin-bottom: 16px; }
p.b { margin-top: 24px; }

Remember

  • Vertical margins collapse inside a BFC, including parent/first-child
  • display: flow-root creates a BFC with no side effects
  • BFCs contain floats and block margin collapse across their edge
  • Flex and grid contexts never collapse margins

Watch out for

  • Adding padding: 1px hacks to stop margin collapse instead of display: flow-root.

Check yourself

  1. A section with no padding or border contains an h1 with margin-top: 40px. Where does the gap appear?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: developer.mozilla.org/en-US/docs/Web/CSS/Guides/Display/Block_formatting_context

Builds on

Unlocks

Nothing builds on this yet.