Skip to content

The Box Model

beginner10 min read

Every Element on the Page Is a Rectangle

Before flexbox, grid, or any layout system — there's the box model. Every single element the browser renders is a rectangular box with four layers: content, padding, border, and margin. And here's what trips people up: the size you think you're setting and the size the browser actually renders are often different. That gap? That's the box model.

Margin collapse alone causes more confusion than any other CSS behavior. But once you understand the exact rules, you stop fighting it and start using it intentionally.

Mental Model

Think of the box model as a picture in a frame. The content is the picture itself. Padding is the matting inside the frame. Border is the frame itself. Margin is the wall space between this frame and the next. Here's the twist: when two frames hang side by side, their wall space overlaps — that's margin collapse. But add a glass pane (border or padding) between them, and each frame keeps its own space.

content-box vs border-box

The box-sizing property changes what width and height control:

content-box (the default)

.box {
  box-sizing: content-box; /* Default */
  width: 200px;
  padding: 20px;
  border: 2px solid black;
}
/* Total rendered width: 200 + 20 + 20 + 2 + 2 = 244px */

With content-box, width: 200px sets only the content area. Padding and border are added on top.

border-box (what you almost always want)

.box {
  box-sizing: border-box;
  width: 200px;
  padding: 20px;
  border: 2px solid black;
}
/* Total rendered width: 200px (padding and border included) */
/* Content area: 200 - 20 - 20 - 2 - 2 = 156px */

With border-box, width: 200px includes content + padding + border. The content area shrinks to accommodate.

The universal reset that every modern project uses:

*, *::before, *::after {
  box-sizing: border-box;
}
Common Trap

Margin is never included in either box-sizing mode. width and height never account for margin. If you set width: 100% on an element with margin: 20px, it will overflow its container by 40px. Use width: auto (the default for block elements) or calc(100% - 40px) instead.

Margin Collapse: The Complete Rules

This is the part that burns people. Vertical margins between adjacent block-level elements collapse -- meaning they overlap rather than stack. It's easily the most misunderstood behavior in CSS.

Rule 1: Adjacent Siblings Collapse

.first { margin-bottom: 30px; }
.second { margin-top: 20px; }
/* Space between them: 30px (not 50px) */
/* The larger margin wins */

Rule 2: Parent and First/Last Child Collapse

If there's nothing separating a parent's margin from its child's margin, they collapse:

.parent { margin-top: 40px; }
.child { margin-top: 20px; }
/* Result: 40px margin above the parent (not 40px + 20px) */
/* The child's margin "escapes" through the parent */

Rule 3: Empty Elements Collapse Their Own Margins

.empty {
  margin-top: 30px;
  margin-bottom: 20px;
  /* No content, padding, border, or height */
}
/* Takes up only 30px of space (larger margin wins) */

Rule 4: Negative Margins

When one margin is negative:

  • Both positive: largest wins
  • One negative, one positive: they are added (30px + -10px = 20px)
  • Both negative: the most negative wins (-30px beats -10px)
.first { margin-bottom: 30px; }
.second { margin-top: -10px; }
/* Space between them: 20px (30 + -10) */

When Margins Do NOT Collapse

Honestly, this list is more important than the collapse rules themselves:

/* 1. Flex or grid items — their margins never collapse */
.flex-container { display: flex; flex-direction: column; }
.flex-container > * { margin: 20px 0; }
/* Full 40px between items, not 20px */

/* 2. Elements with overflow other than visible */
.parent { overflow: hidden; } /* or auto, scroll */
/* Child margins can't escape through parent */

/* 3. Elements with border or padding separating them */
.parent { padding-top: 1px; }
/* That 1px padding blocks parent-child collapse */

/* 4. Floated elements */
/* 5. Absolutely or fixed positioned elements */
/* 6. Inline-block elements */
/* 7. Elements that establish a BFC (Block Formatting Context) */
Execution Trace
Adjacent siblings
.box-a { margin-bottom: 40px } .box-b { margin-top: 25px }
Margins collapse: gap = 40px (larger wins)
Parent-child
.parent { margin: 0 } .child:first-child { margin-top: 30px }
Child's 30px escapes through parent (no border/padding blocking)
Add padding
.parent { padding-top: 1px }
Now child's margin stays inside — no collapse
Use flexbox
.parent { display: flex; flex-direction: column }
Flex items never collapse margins — full spacing preserved

Production Scenario: The Disappearing Spacing

You will hit this bug. Everyone does. You add margin-top to the first child and the margin appears above the parent instead of inside it:

<div class="card">
  <h2 class="card-title">Hello</h2>
</div>
.card {
  background: white;
  /* No padding, no border — nothing blocking collapse */
}

.card-title {
  margin-top: 24px;
  /* This margin escapes through .card's top edge */
  /* The card appears to have margin-top: 24px */
  /* But the space is ABOVE the card background, not inside it */
}

Fixes:

/* Fix 1: Add padding to the parent (most common) */
.card { padding: 24px; }
.card-title { margin-top: 0; }

/* Fix 2: Add a border (even transparent) */
.card { border-top: 1px solid transparent; }

/* Fix 3: Use overflow */
.card { overflow: hidden; }

/* Fix 4: Use display: flow-root (creates BFC) */
.card { display: flow-root; }
What developers doWhat they should do
Expecting width: 100% + padding to fit inside the container
With content-box (default), padding is added outside the width
Use box-sizing: border-box so width includes padding and border
Expecting margin-top: 20px + margin-bottom: 20px = 40px gap between siblings
Margin collapse is intentional: it keeps typographic rhythm consistent
Adjacent vertical margins collapse — the larger margin wins
Setting margin-top on the first child expecting space inside the parent
Without border/padding/BFC, child margins escape through the parent
Use padding on the parent, or create a BFC with overflow or display: flow-root
Assuming margin collapse applies in all layout contexts
These contexts establish their own formatting contexts that prevent collapse
Flex items, grid items, floats, and absolutely positioned elements never collapse margins
Quiz
An element has box-sizing: border-box, width: 300px, padding: 20px on each side, and border: 5px solid. What is the content area width?
Quiz
.parent has no padding, border, or overflow set. .child:first-child has margin-top: 40px. Where does the 40px space appear?
Quiz
Two flex items in a column layout have margin-bottom: 20px and margin-top: 20px respectively. What's the gap between them?
Key Rules
  1. 1Use box-sizing: border-box universally — width includes content + padding + border
  2. 2Margin is never included in box-sizing calculations
  3. 3Vertical margins collapse between adjacent siblings, between parent and first/last child, and on empty elements
  4. 4Margins DO NOT collapse in flex, grid, float, absolutely positioned, or overflow contexts
  5. 5To prevent parent-child collapse: add padding, border, overflow, or display: flow-root to the parent