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.