📦 The Box Model in Depth
Every element on a page is a rectangular box. The box model describes the four layers that make up that box and how their sizes combine — and it is the single most important idea for building predictable layouts. Get comfortable here and Flexbox, Grid, and everything after will make far more sense.
🎯 Learning Objectives
By the end of this lesson, you will be able to:
- Name the four box-model layers — content, padding, border, margin — and what each controls
- Explain how
box-sizing: border-boxchanges size calculations and why it is the sane default - Predict margin collapsing and know how to prevent it
- Size elements with
width/height,min/max, andaspect-ratio - Handle content that doesn't fit using the
overflowfamily of properties
Estimated Time: 40–50 minutes • Difficulty: Beginner
Hands-on: Build a card component and prove you can predict its exact rendered width.
In This Lesson
What Is the Box Model?
In CSS, every element is a box — even a single word inside a <span>. The box model defines how much space that box takes and how its layers nest. Once you can picture the box, unexpected gaps and stubborn widths stop being mysteries.
📦 A shipping analogy: the content is the item, the padding is the bubble wrap around it, the border is the cardboard box, and the margin is the empty space you leave between this box and the next one on the shelf.
The Four Layers
From the inside out: content, then padding, then border, then margin. Each is its own concentric layer.
Padding
padding: 20px; /* all four sides */
padding: 10px 20px; /* top/bottom | left/right */
padding: 10px 20px 15px 25px; /* top | right | bottom | left (clockwise) */
padding-inline: 1rem; /* logical: left & right in LTR */
Padding is inside the border, is covered by the element's background, and is part of the clickable area. It cannot be negative.
Border
border: 2px solid var(--border-color); /* width | style | color */
border-radius: 8px; /* rounded corners */
border-radius: 50%; /* a circle, on a square box */
border-block-end: 3px dashed hotpink; /* one logical edge */
Margin
margin: 16px;
margin: 0 auto; /* horizontal centring for a block with a set width */
margin-top: -8px; /* negative margins pull an element toward its neighbour */
Unlike padding, margin can be negative, and vertical margins can collapse — a quirk covered in its own section below.
box-sizing: the Big One
Here is the single most useful thing in this lesson. By default (content-box), the width you set applies to the content only — padding and border are added on top, making the box bigger than you asked for.
/* Default: content-box */
.a {
box-sizing: content-box;
width: 200px;
padding: 20px;
border: 5px solid;
}
/* Rendered width = 200 + 20 + 20 + 5 + 5 = 250px 😖 */
/* border-box: width INCLUDES padding and border */
.b {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 5px solid;
}
/* Rendered width = exactly 200px 😊 */
border-box, the number you type is the number you get. This is why almost every codebase resets to it globally.✅ The universal reset
Put this at the top of your stylesheet and never fight surprise widths again:
*, *::before, *::after {
box-sizing: border-box;
}
border-box makes percentage widths, padding, and borders compose predictably — indispensable for responsive layouts.
Margins & Collapsing
The most surprising box-model behaviour is margin collapsing: when two vertical margins meet, they don't add up — they merge into a single margin equal to the larger of the two.
.top { margin-bottom: 20px; }
.bottom { margin-top: 30px; }
/* The gap between them is 30px, NOT 50px */
The rules
- Only vertical margins collapse; horizontal margins never do.
- Adjacent siblings collapse to the larger of the two margins.
- A parent and its first/last child can collapse together if nothing (padding, border, or content) separates them.
💡 How to stop a collapse
Insert something between the margins: a sliver of padding or a border on the parent, or switch the container to a flex or grid context — margins never collapse inside those. In modern layouts, many developers sidestep the issue entirely by using gap instead of margins.
⚠️ Negative margins are a sharp tool
Negative margins genuinely pull elements out of flow (useful for overlaps and bleed effects), but they make layouts hard to reason about. Prefer gap, transform: translate(), or positioning when you can.
Width, Height & Aspect Ratio
Dimensions accept absolute lengths, percentages (of the parent), viewport units, and intrinsic keywords.
.box {
width: 60%; /* of the parent's content width */
max-width: 640px; /* but never wider than this */
min-height: 200px; /* at least this tall, grow with content */
height: auto; /* let content decide — the usual choice */
}
/* Viewport and intrinsic sizing */
.full { width: 100vw; height: 100vh; }
.snug { width: fit-content; } /* as wide as content, up to available space */
.tight { width: min-content; } /* as narrow as the longest unbreakable word */
✅ Sizing best practices
- Prefer
max-widthover a fixedwidthso content can shrink on small screens. - Avoid fixing
heighton text containers — let content set it and usemin-heightif you need a floor. - Reach for relative units (
%,rem,vw) for responsive behaviour.
aspect-ratio
The modern aspect-ratio property locks a width-to-height ratio, which is perfect for media and uniform cards — no more padding-hack.
.video { width: 100%; aspect-ratio: 16 / 9; } /* height follows automatically */
.avatar { width: 64px; aspect-ratio: 1; } /* a perfect square */
Overflow Handling
When content is bigger than its box, overflow decides what happens.
overflow: visible; /* default — content spills outside the box */
overflow: hidden; /* extra content is clipped away */
overflow: scroll; /* scrollbars always shown */
overflow: auto; /* scrollbars appear only when needed */
/* Axis-specific */
overflow-x: auto;
overflow-y: hidden;
| Value | Clips? | Scrollbars | Typical use |
|---|---|---|---|
visible | No | None | Default flow |
hidden | Yes | None | Cropping, preventing layout breaks |
scroll | Yes | Always | Reserving scroll space to avoid layout shift |
auto | Yes | Only if needed | Chat panes, code blocks, fixed-height regions |
Truncating text
Combine overflow with text properties for the classic ellipsis. A single line needs three properties; multi-line uses line-clamp:
.one-line {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.three-lines {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
The Box Model in Layouts
The box model doesn't disappear when you adopt modern layout systems — it underpins them.
| Layout | How the box model applies |
|---|---|
| Normal flow | Block boxes stack; vertical margins collapse; margin: 0 auto centres. |
| Flexbox | No margin collapsing; box-sizing affects how flex-basis is measured; use gap for spacing. |
| Grid | Items fill cells; padding/border still count inside the cell; gap replaces inter-item margins. |
💡 Debugging box-model issues
Open your browser's DevTools and inspect an element — the box-model diagram shows exact content, padding, border, and margin values. For a quick visual audit, temporarily outline everything:
* { outline: 1px solid red; } /* outline, not border — it won't shift layout */
Hands-on Exercise
🏋️ Predict-the-Width Card
Objective: Build a card and prove you can calculate its rendered size under both box-sizing models.
Instructions:
- Create a
.cardwithwidth: 300px,padding: 24px, andborder: 2px solid. - First set
box-sizing: content-boxand calculate the rendered width by hand, then verify in DevTools. - Switch to
box-sizing: border-boxand calculate again. Note which one matched yourwidthdeclaration. - Add a heading and a paragraph, then use
marginto space them — and observe whether their vertical margins collapse. - Bonus: add a circular avatar with
aspect-ratio: 1andborder-radius: 50%.
💡 Hint
Rendered width in content-box = width + left/right padding + left/right border. In border-box, padding and border are subtracted from the width, so the outer size stays put.
✅ Answer
content-box: 300 + 24 + 24 + 2 + 2 = 352px rendered.
border-box: exactly 300px rendered (content area shrinks to 300 − 24 − 24 − 2 − 2 = 248px).
.card {
box-sizing: border-box;
width: 300px;
padding: 24px;
border: 2px solid var(--border-color);
border-radius: 8px;
}
.card .avatar {
width: 56px;
aspect-ratio: 1;
border-radius: 50%;
}
🎯 Quick Quiz
Question 1: With box-sizing: content-box, an element has width: 200px, padding: 20px, and border: 5px solid. What is its rendered width?
Question 2: Two stacked block elements have a 30px bottom margin and a 20px top margin respectively. How much space sits between them?
Question 3: Which overflow value shows scrollbars only when content actually overflows?
Summary & Quiz
🎉 Key Takeaways
- Every element is a box with four layers: content, padding, border, margin.
box-sizing: border-boxmakes the declared width the rendered width — reset it globally.- Vertical margins collapse to the larger value; padding, borders, and flex/grid contexts prevent it.
- Prefer
max-widthandmin-heightover fixed dimensions; useaspect-ratiofor media. overflow: autoadds scrollbars only when needed; combine overflow with text properties to truncate.
📚 Further Reading
🚀 What's Next?
With the box model solid, we go back to selectors and get precise: Attribute and Pseudo-class Selectors — targeting elements by their attributes and states.
🎉 Boxed up!
You can now predict any element's size and spacing. This foundation carries straight into Flexbox and Grid.