Topic 5.3
Margins in Depth
In one line
Margins can be auto (to centre a block), negative (to pull boxes closer or overlap them), and vertical margins between blocks collapse into one, which explains most mystery gaps in CSS.
Think of it like this
Two people standing in a queue who each want "personal space". One wants 1 metre, the other wants 2 metres. They don't stand 3 metres apart; they stand 2 metres apart, because the bigger wish already covers the smaller one. That's margin collapsing: touching vertical margins share the space instead of adding up.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- auto margin
margin: autolets the browser fill the leftover space. On both sides of a block, it centres the block.- Negative margin
- A margin below zero. It pulls the box (or its neighbour) closer, and can make boxes overlap.
- Margin collapsing
- Two touching vertical margins becoming one, the size of the larger, instead of adding up.
- Normal flow
- The default layout: blocks stacked top to bottom, inline content in lines. See Topic 6.1.
- Block formatting context (BFC)
- A self-contained layout area. Margins inside it don't collapse with margins outside it, and it contains floats.
- flow-root
- A
displayvalue that makes a normal block which also starts a new BFC. - Block direction
- The direction blocks stack in: top to bottom for English text.
Step by step
01Centre a block with auto margins
A block is as wide as its parent unless you limit it. Give it a max-width and auto left and right margins: the browser divides the leftover space in two.
.page {
max-width: 600px;
margin-inline: auto; /* same as margin-left: auto; margin-right: auto; */
}02Watch two margins collapse
A heading with margin-bottom: 30px sits above a paragraph with margin-top: 20px. The gap between them is 30px, the larger of the two, not 50px.
03See a child's margin escape its parent
A card has a coloured background and an h2 inside with margin-top: 20px. You expect a 20px coloured strip above the heading. Instead the gap appears above the card, outside its background, because the child's margin collapsed through the parent.
.card { background: lavender; } /* no border, no padding */
.card h2 { margin-top: 20px; } /* this margin escapes above .card */04Stop the escape
Separate the margins: give the parent some padding-top, a border, or make it a new formatting context with display: flow-root. Now the 20px stays inside the card.
.card {
background: lavender;
display: flow-root; /* new block formatting context */
}05Use a negative margin on purpose
An avatar that overlaps the bottom of a banner: pull it up by half its height with a negative top margin. The text after it moves up too, because the avatar now takes less vertical space.
.avatar {
width: 64px;
height: 64px;
margin-top: -32px; /* half of its height */
}06Pick a margin habit
Many teams only use margin-bottom (or only margin-top) for vertical spacing, so siblings never have two margins to collapse, and use gap inside flex and grid containers.
Try it yourself
- 1
Predict the collapsed gap
In the collapsing example, change
.btomargin-top: 50px, then tomargin-top: -10px. Predict the gap each time before running (the larger wins: 50; mixed signs are summed: 30 + −10 = 20). - 2
Stop the escape with padding
Remove
display: flow-rootfrom.rootand instead give itpadding-top: 1px. Predict the child's distance from the parent's top (20 + 1 = 21), then run. - 3
Push with one auto
In the first example, change
.righttomargin: 8px auto 0 0. Which side does it move to now?
Code & diagrams
The 160px of leftover space is split in two when both sides are auto, and all goes to one side when only one is.
Preview
Console
Nothing logged yet.Expected console output
centred: left gap 80 right gap 80
pushed right: left gap 160 right gap 0In the plain parent, the blue background starts right at the child: the child's 20px margin collapsed with the parent's 10px and escaped above it.
Preview
Console
Nothing logged yet.Expected console output
gap between A and B: 30
plain parent: child sits 0 px below the parent's top
flow-root parent: child sits 20 px below the parent's topPreview
Console
Nothing logged yet.Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Try to centre vertically with auto margins
Give a child inside a 300px-tall block parent margin: auto and expect it to sit in the middle.
Break #2
The mystery gap above a header
Put an <h1> (which has a default top margin) as the first child of a coloured <header> with no padding.
Myth vs fact
Myth
Margins always add up: 30px + 20px = 50px.
Fact
Vertical margins between blocks in normal flow collapse to the larger one (30px). Horizontal margins, and margins of flex, grid, inline-block, floated and absolutely positioned boxes, do add up.
Myth
margin: auto centres an element both ways.
Fact
In normal flow it only centres horizontally, and only for a block with a width smaller than its parent. Vertical centring with auto margins needs Flexbox, Grid or absolute positioning with inset: 0.
Myth
Negative margins are a bug or a hack.
Fact
They're valid CSS with defined behaviour. Use them for deliberate overlaps or to cancel a parent's padding, but prefer clearer tools (gap, positioning, grid overlap) when they fit.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Collapsing is resolved per spec (CSS 2.1 §8.3.1): positive margins take the max, negative take the min, mixed are summed as max(positive) + min(negative). Several margins can collapse together in a chain (parent top, first child top, grandchild top) into one.
- ▸
margin-trimlets a container trim the margins of its first and last children, but it isn't supported in every major browser yet (check caniuse.com). Until it is, use:first-child { margin-top: 0 }or the owl selector* + * { margin-top: 1em }(spacing only between siblings). - ▸
Percent margins resolve against the containing block's inline size (width in horizontal writing) on all four sides, like padding.
- ▸
When a parent's
heightisauto, its bottom margin collapses with its last child's bottom margin; giving it amin-heightother than zero or a setheightstops that bottom collapse.
Remember this
- 1
margin: autoon the left and right of a block with a set width splits the leftover horizontal space equally, so the block is centred in its parent:.page { width: 600px; margin: 0 auto; }(ormax-widthfor a box that can shrink on phones). Only one sideautopushes the box to the other side:margin-left: automoves it to the right. In normal block layout,margin-top: autoandmargin-bottom: autocompute to0, so they don't centre vertically (they do in Flexbox and Grid, Phases 7 and 8). - 2
Margins can be negative. A negative
margin-topormargin-leftpulls the box up or left, on top of whatever is there. A negativemargin-bottomormargin-rightpulls the next box closer. Negative margins are useful for small overlaps (an avatar that pokes out of a card header) or to let a child break out of its parent's padding, but they make layouts harder to reason about, so use them sparingly. - 3
Margin collapsing happens only to vertical (block-direction) margins of block boxes in normal flow. When a bottom margin touches a top margin with nothing between them, the two become one margin, the size of the larger. A paragraph with
margin-bottom: 30pxabove one withmargin-top: 20pxgives a 30px gap, not 50px. If one margin is negative, they are added (30 + −10 = 20); if both are negative, the most negative wins. - 4
There are three cases where margins collapse. Adjacent siblings: the bottom margin of one block and the top margin of the next. Parent and first or last child: if the parent has no top border, no top padding and nothing inline before the child, the child's top margin escapes through the parent and becomes the parent's margin (the same for the bottom). Empty blocks: a block with no height, padding, border or content collapses its own top and bottom margins together.
- 5
Collapsing stops when something separates the margins: a border or padding on the parent, inline content (text) in between, a set
heightormin-height(for the bottom case), or a new block formatting context (BFC). A BFC is a self-contained layout area: margins inside don't collapse with margins outside. You create one withdisplay: flow-root(Topic 5.4),overflowother thanvisible(Topic 5.6), or by making the parent a flex or grid container. - 6
Margins never collapse horizontally, never between flex or grid items, never on floated or absolutely positioned boxes, and never on
inline-blockboxes. This is one reason many developers now space items withgapin Flexbox and Grid, or only use margin in one direction (for example, onlymargin-bottom), so collapsing never surprises them.
Explain it without notes
What is margin collapsing and when does it happen?
Why does margin: 0 auto centre a block, and what does it need to work?
A child's top margin shows up above its parent's background. Why, and what are three ways to fix it?
Give two legitimate uses of negative margins and one risk.
In which situations do margins never collapse?
Practice
Centre a .notice that is at most 500px wide in its parent, then log the computed margin-left when the parent is 700px wide.
Two paragraphs: the first has margin-bottom: 24px, the second margin-top: -8px. Both are 30px tall blocks. Log the gap between them.
Fix a .card whose first child h2 margin escapes, without changing the h2. Log the distance from the card's top to the h2's top.
Trade-offs
- ↔
Margin collapsing is handy for text (a heading's bottom and a paragraph's top don't double up), but surprising in components. Using
gapor one-direction margins avoids it, at the cost of not getting the automatic "take the larger" behaviour. - ↔
Negative margins give quick overlaps without positioning, but they tie elements' sizes together; changing the avatar's height means changing the margin too.
Done when you can
I can centre a block horizontally with auto margins and explain why it works.
I can predict the gap between two blocks with collapsing margins, including negative ones.
I can spot a child margin escaping its parent and fix it three ways.
I can use a negative margin deliberately for an overlap.
I know where margins never collapse (flex, grid, inline-block, floats, horizontal).