The Box Model
Every element in CSS is a rectangular box. Understanding the box model means understanding what makes up that rectangle: content, padding, border, and margin. These four layers determine an element's size and spacing.
The Four Layers
Content is the innermost layer—text, images, or child elements.
Padding is transparent space between content and border. It expands the element's background color.
Border is a visible line around the padding. It has width, style, and color.
Margin is transparent space outside the border. It pushes other elements away.
.box {
width: 200px; /* Content width */
padding: 20px; /* Inside spacing */
border: 2px solid black; /* Visible edge */
margin: 10px; /* Outside spacing */
}box-sizing: The Critical Property
By default, width and height set the content box size. Padding and border add to this:
.box {
width: 200px;
padding: 20px;
border: 2px solid black;
}
/* Total width: 200 + (20 × 2) + (2 × 2) = 244px */This is box-sizing: content-box. It's unintuitive—when you set width: 200px, the element isn't 200px wide.
box-sizing: border-box changes the calculation. width now includes padding and border:
.box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 2px solid black;
}
/* Total width: 200px (padding and border included) */
/* Content width: 200 - (20 × 2) - (2 × 2) = 156px */This matches intuition. If you set width: 200px, the element is 200px wide.
Always use border-box. Set it globally:
*, *::before, *::after {
box-sizing: border-box;
}This is a universal best practice. You'll never want content-box.
Margin Collapse
Adjacent vertical margins collapse—they merge into a single margin equal to the larger of the two:
.box-1 { margin-bottom: 30px; }
.box-2 { margin-top: 20px; }
/* Space between boxes: 30px (not 50px) */The 30px margin "wins" and the 20px margin disappears.
When Margins Collapse
Margins collapse when:
- Elements are in normal flow (not floated or positioned)
- No border, padding, or content separates them
- Both are block-level
Margins do not collapse when:
- Parent has padding or border
- Parent creates a new formatting context (flex, grid,
display: flow-root) - Elements are inline or inline-block
- One element is positioned
Why Margin Collapse Exists
Margin collapse solves the "double space" problem. Headings have default top and bottom margins. Without collapse, two headings would have double spacing between them.
<h2>First Heading</h2> <!-- margin-bottom: 20px -->
<h2>Second Heading</h2> <!-- margin-top: 20px -->
<!-- Without collapse: 40px gap. With collapse: 20px gap. -->Preventing Margin Collapse
If you don't want collapse, create a formatting context:
.container {
display: flow-root; /* Creates formatting context */
}Or add a minimal border:
.container {
border-top: 1px solid transparent;
}Though a better approach is to use padding on the parent instead of margins on children.
Negative Margins
Unlike padding, margins can be negative. This pulls the element in the opposite direction:
.overlap {
margin-top: -20px; /* Moves element up, potentially overlapping previous element */
}
.expand {
margin-left: -10px;
margin-right: -10px;
/* Content extends 10px beyond container on each side */
}Negative margins are useful for:
- Breaking elements out of containers
- Overlapping decorative elements
- Adjusting optical alignment
But use sparingly—negative margins can create unexpected layout shifts.
outline: The Layout-Free Border
outline draws a line around an element like border, but doesn't affect layout:
.focus-indicator {
outline: 2px solid blue;
outline-offset: 2px; /* Space between element and outline */
}Outlines:
- Don't add to element dimensions
- Don't trigger layout recalculation
- Can overlap adjacent elements
- Are drawn on top of everything (including borders)
Use outline for focus indicators (:focus) or debugging—never for layout structure.
Intrinsic Sizing
Instead of fixed dimensions, you can size elements based on their content:
min-content — Shrinks to the smallest possible width without overflow (usually the longest word):
.shrink {
width: min-content;
}max-content — Expands to fit all content on one line (no wrapping):
.expand {
width: max-content;
}fit-content — Uses max-content but respects container constraints:
.button {
width: fit-content; /* As wide as text, but not wider than parent */
}These are useful for components that should size to their content:
.tag {
width: fit-content;
padding: 0.25em 0.75em;
}
/* Tag is as wide as its text plus padding */aspect-ratio: Dimension Locking
aspect-ratio locks an element's proportions:
.video-container {
aspect-ratio: 16 / 9;
width: 100%;
}
/* Height automatically calculated to maintain 16:9 ratio */This prevents layout shift when images or videos load:
.thumbnail {
aspect-ratio: 4 / 3;
width: 200px;
background: #f0f0f0;
}
/* Reserves 150px height before image loads */Before aspect-ratio, you'd use the padding-hack:
/* Old approach—no longer necessary */
.video-wrapper {
padding-bottom: 56.25%; /* 9/16 * 100 = 56.25% */
position: relative;
}Always use aspect-ratio for new code.
Hardcoded Dimensions for Dynamic Content
When content loads asynchronously (images, ads, embeds), reserve space with hardcoded dimensions to prevent layout shift:
.avatar {
width: 48px;
height: 48px;
background: #e0e0e0;
}
.ad-slot {
width: 300px;
height: 250px;
background: #f5f5f5;
}The background color shows while content loads, and the fixed dimensions prevent the page from jumping when content appears.
For images, use aspect-ratio with width or height:
<img src="photo.jpg" width="800" height="600" style="width: 100%; height: auto;">The browser calculates the space before the image loads, preventing shift.
Check Your Understanding
With `box-sizing: border-box`, `width: 300px`, `padding: 20px`, and `border: 5px`, what is the content width?
Two block elements have `margin-bottom: 40px` and `margin-top: 25px`. How much space is between them?
Why use `box-shadow: 0 0 0 1px` instead of `border: 1px solid`?
Practice
Summary
- Box model layers: Content, padding, border, margin (inside to outside).
box-sizing: border-box: Makeswidthinclude padding and border. Always use this globally.- Margin collapse: Adjacent vertical margins merge into the larger margin.
- Prevent collapse: Use
display: flow-root, padding, or borders on the parent. - Negative margins: Pull elements in the opposite direction. Useful for breakout layouts.
outline: Draws around elements without affecting layout. Use for focus indicators.- Box shadows for borders:
box-shadow: 0 0 0 1pxcreates a "border" without layout shift. - Intrinsic sizing:
min-content,max-content,fit-contentsize elements to their content. aspect-ratio: Locks proportions to prevent layout shift during image loading.- Hardcode dynamic dimensions: Reserve space for async content to prevent layout shift.