The Box Model — Margin, Border, Padding, Content
Every element on the page is a box. Understanding the box model precisely is what makes every later layout concept make sense.
Every Element Is a Rectangular Box, Built From Four Layers
No matter how an element looks on the page — text, an image, a button, an entire layout section — the browser renders it as a rectangular box, built from exactly four concentric layers, always in the same order, from the inside out: content, padding, border, and margin. Understanding this stack precisely is the single most load-bearing piece of CSS knowledge in the entire language — nearly every layout bug you will ever debug eventually traces back to a misunderstanding of one of these four layers.
.card {
width: 300px; /* the CONTENT box */
padding: 20px; /* space INSIDE the border, around the content */
border: 2px solid #333; /* a visible line around the padding */
margin: 16px; /* space OUTSIDE the border, pushing other elements away */
}Content is the innermost box — the actual text, image, or nested elements. Its size is controlled by width and height. Padding is transparent space between the content and the border — it is still considered "inside" the element, and it takes on the element's background color. Border is a visible (or invisible, if unset) line drawn around the padding. Margin is transparent space entirely outside the border — it is not part of the element at all, and its only job is to push neighboring elements away.
Background color covers content AND padding, never margin
A detail that trips up beginners constantly: setting background on an element fills the content box and the padding — the colored area extends all the way out to the border. Margin is always transparent, by definition, since it exists entirely outside the element's own box.
.badge {
background: #f97316;
padding: 8px 16px;
margin: 12px;
}
/* The orange background extends through the padding right up to the
border edge. The 12px margin around the badge stays fully transparent
— you are seeing through to whatever is behind the badge there. */box-sizing: content-box vs border-box — The Property That Changes What width Means
Here is the detail that causes the most confusion in the entire box model: by default, width and height only control the size of the content box. Padding and border are added on top of that width, making the element's actual rendered size larger than the width you set.
.box {
box-sizing: content-box; /* this is the default, even if never written */
width: 300px;
padding: 20px;
border: 5px solid black;
}
/* Actual rendered width = 300 (content) + 20 + 20 (left+right padding)
+ 5 + 5 (left+right border)
= 350px, not 300pxThis is rarely what anyone actually wants — you set a width expecting the element to be exactly that wide, and instead it grows past it the moment you add padding or a border. The fix is a different value for box-sizing, which changes what width actually measures.
.box {
box-sizing: border-box;
width: 300px;
padding: 20px;
border: 5px solid black;
}
/* Actual rendered width = exactly 300px.
Padding and border are now carved OUT of the 300px, not added on top.
The content area shrinks to make room for them instead. */Why nearly every real stylesheet resets to border-box globally
Because content-box's "width doesn't mean width" behavior is confusing and rarely useful, the near-universal convention in real production CSS is a single reset rule at the very top of the stylesheet that switches every element to border-box — a pattern you will see at the top of essentially every professional codebase, CSS framework, and starter template.
*, *::before, *::after {
box-sizing: border-box;
}
/* From this point on, every width/height you set anywhere in the
stylesheet means the TOTAL rendered size — padding and border are
automatically absorbed into it, not added on top. */box-sizing first — it is very often the actual cause.Setting Padding, Border, and Margin Per Side
Padding and margin both accept a shorthand that can set one, two, three, or four values at once — the number of values changes what each one means, and misremembering the order is a common source of "why is my spacing lopsided" bugs.
padding: 20px; /* all four sides */
padding: 20px 40px; /* top+bottom, left+right */
padding: 20px 40px 10px; /* top, left+right, bottom */
padding: 20px 40px 10px 5px; /* top, right, bottom, left — CLOCKWISE from top */The four-value form always goes clockwise starting from the top: top, right, bottom, left. This is worth memorizing precisely rather than guessing, since getting the order wrong produces a layout that is subtly, confusingly asymmetric rather than obviously broken.
.box {
margin-top: 20px;
margin-right: 40px;
margin-bottom: 10px;
margin-left: 5px;
}
/* Equivalent to: margin: 20px 40px 10px 5px; */Border's shorthand bundles three different properties, not four sides
Border's shorthand works differently — a single border declaration sets border-width, border-style, and border-color together, and each of those can independently be set per side.
border: 2px solid #333;
/* equivalent to:
border-width: 2px;
border-style: solid;
border-color: #333;
*/
/* Per-side border — only a left accent border, nothing else */
.callout {
border-left: 4px solid #f97316;
}border-style is required for a border to render at all — omitting it (writing only border-width and border-color) produces no visible border, since the default style is none. This is a genuinely common early mistake: setting a width and color and being confused why nothing appears.Margin Collapsing — When 20px + 20px Becomes 20px, Not 40px
This is the single most surprising piece of default CSS behavior for anyone learning the box model, and it catches experienced engineers off guard too, not just beginners. In certain situations, the vertical margins of two elements do not add together — they collapse into a single margin equal to the larger of the two, not the sum.
p {
margin-top: 20px;
margin-bottom: 20px;
}<p>First paragraph.</p>
<p>Second paragraph.</p>
/* You might expect 40px between them: 20px (first's margin-bottom)
+ 20px (second's margin-top).
What actually happens: the two margins COLLAPSE into a single 20px
gap — the LARGER of the two touching margins, not their sum. */The rule applies specifically to adjacent vertical margins — a bottom margin touching a following sibling's top margin. Horizontal margins never collapse, and margins separated by padding, a border, or actual content in between do not collapse either, because they are no longer directly touching.
.a { margin-bottom: 30px; }
.b { margin-top: 10px; }
/* Gap between .a and .b is 30px — the larger of the two — not 40px,
and not 10px. This is what "collapse" specifically means:
max(30, 10), not addition. */Parent-child margin collapsing — an even more surprising case
Margins can also collapse between a parent and its first or last child, if nothing separates them — no border, no padding, no content on that side of the parent. The child's margin effectively "escapes" the parent entirely.
<div class="parent">
<p class="child">Hello</p>
</div>.parent {
background: lightblue; /* no border, no padding */
}
.child {
margin-top: 40px;
}
/* You might expect 40px of blue space at the TOP of .parent, then the
text starting. Instead, the entire .parent box gets pushed down 40px
— the child's margin "escaped" through the parent, because nothing
(no border/padding) was there to contain it. */1px solid transparent), or setting overflow: hidden or display: flow-root on the parent stops the collapse — any of these creates a real containing boundary the child's margin cannot pass through..parent {
background: lightblue;
padding-top: 1px; /* even 1px is enough to block the collapse */
}
/* Now the child's 40px top margin stays fully INSIDE .parent, as
originally expected. */Margin collapsing does not apply to Flexbox or Grid children, only to normal ("block") document flow — one of many reasons modern layouts built with Flexbox or Grid (covered later in this track) sidestep this particular surprise entirely.
Inline Elements Play by Different Box-Model Rules
Not every element applies the box model identically — display: inline elements (like <span> and <a> by default) ignore several box-model properties that block-level elements respect fully.
span {
width: 300px;
height: 100px;
background: yellow;
}
/* Both width and height are silently ignored on an inline element.
Its size is determined entirely by its content — the text inside it
— and nothing else. This is one of the most common "why isn't my
CSS working" moments for beginners. */span {
margin-top: 40px;
margin-bottom: 40px;
margin-left: 10px; /* this ONE still works */
}
/* margin-top and margin-bottom have no visual effect on an inline
element — they do not push surrounding lines apart. Horizontal
margin (left/right) DOES work normally on inline elements. */Vertical padding and border technically still render visually on inline elements — you will see a colored background or a border line — but they do not affect the surrounding block layout the way they would on a block element; they can visually overlap the line above or below rather than pushing it away.
display: inline-block. It keeps the element flowing inline with surrounding text (unlike display: block, which forces it onto its own line) while restoring full support for width, height, and vertical margin — the best of both behaviors. This gets its own full treatment, alongside position, in the Display & Positioning module later in this phase.Block-level elements, by contrast, respect every box-model property fully
div {
display: block; /* the default for <div> */
width: 300px;
height: 100px;
margin: 20px;
}
/* Every value here applies exactly as written — the element is exactly
300x100px, plus a full 20px margin in every direction. */A Broken Checkout Layout at an Austin Meal-Kit Delivery Startup
An engineer at an Austin-based meal-kit delivery startup builds a three-column price-summary row for the checkout page — each column meant to be exactly one-third of a 900px container, with padding and a border for visual separation.
.summary-row {
width: 900px;
}
.summary-col {
width: 300px;
padding: 16px;
border: 1px solid #ddd;
float: left;
}In the browser, the third column wraps onto its own line below the first two, breaking the layout entirely — despite 300px × 3 = 900px, which should fit exactly inside a 900px container.
What DevTools' box model diagram shows
Hovering each column in DevTools reveals the real rendered width is not 300px at all — it is 300 + 16 + 16 (padding) + 1 + 1 (border) = 334px. Three columns at 334px each is 1,002px — 102px wider than the 900px container, which is exactly why the third one wraps. This is box-sizing: content-box (the browser default, Part 02) doing precisely what it is specified to do: padding and border added on top of the declared width, not absorbed into it.
The fix
*, *::before, *::after {
box-sizing: border-box;
}
/* No other CSS needs to change. Every .summary-col is now genuinely
300px total, padding and border included — three of them fit
exactly inside the 900px .summary-row, as originally intended. */The team adds the reset globally, at the very top of the site's main stylesheet, so every future component benefits automatically rather than requiring this exact debugging session again on the next multi-column layout. This is precisely why the border-box reset from Part 02 is close to universal in real production CSS — it removes an entire, extremely common category of layout bug before it can happen.
Four Misconceptions About the Box Model
5 Interview Questions — With Complete Answers
Box Model Mistakes Beginners Make Constantly
Rendering Bugs You Will Hit — And Exactly Why
🎯 Key Takeaways
- ✓Every element is a box built from four concentric layers, always in the same order: content, padding, border, margin.
- ✓Padding and border take on the element's background color; margin never does — it is always transparent, pure spacing outside the box.
- ✓box-sizing: content-box (the default) adds padding and border ON TOP of width/height; box-sizing: border-box absorbs them into it instead. Nearly every real project resets globally to border-box.
- ✓Vertical margins between adjacent elements collapse to the LARGER value, not the sum — this applies to sibling-to-sibling and parent-to-first/last-child margins in normal document flow.
- ✓Give a parent padding, a border, overflow: hidden, or display: flow-root to stop a child's margin from collapsing through it.
- ✓Inline elements ignore width, height, and vertical margin entirely — use inline-block (or block) when an inline-flowing element needs real box dimensions.
- ✓border-style must be set (directly or via the border shorthand) or no border renders at all, regardless of border-width and border-color.
- ✓The padding/margin/border shorthand accepts 1-4 values; the 4-value form always goes clockwise from the top: top, right, bottom, left.
What comes next
Module 19 covers colors, units, and typography — every unit type you will type in a real stylesheet, every color format, font stacks, and the fundamentals of font-weight and line-height.
Module 19 → Colors, Units & TypographyDiscussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.