Core Frontend
The CSS Box Model: Everything That Actually Matters
A complete, visual guide to the CSS box model — content, padding, border, margin, box-sizing, margin collapsing, logical properties, and the gotchas that bite in real layouts.
Every element on a page is a rectangular box. Layout, spacing, alignment, and most "why is this 8px off?" bugs come down to one thing: how that box is measured. The box model is the rulebook for that measurement, and once it is concrete in your head, CSS layout stops feeling like guesswork.
The box model answers one question: when you set
width,height,padding,border, andmargin, how big is the element, and where does the next one sit?
The Four Layers
Every box is built from four nested layers, from the inside out: content, padding, border, and margin.
- Content — where your text, images, and child elements live. Its size is driven by
width/height(and theirmin-/max-variants). - Padding — transparent space inside the border. It shares the element's background.
- Border — a visible (or invisible) edge with width, style, and color.
- Margin — transparent space outside the border that separates the box from its neighbors. It never has a background.
The One That Trips Everyone: box-sizing
Here is the question that causes the most confusion: does width: 200px mean the content is 200px, or the whole box is 200px? The answer depends on box-sizing.
content-box(the default):widthsizes only the content. Padding and border are added on top, so the rendered box is wider than the number you wrote.border-box:widthsizes the content + padding + border together. The number you write is the real, on-screen width. Content shrinks to make room.
This is why nearly every codebase starts with a global reset:
*,
*::before,
*::after {
box-sizing: border-box;
}
With border-box, width: 50% plus padding: 20px still fits in half the container — no overflow math in your head. Treat this reset as a default, not an option.
Content: width, height, and Their Limits
The content area is controlled by:
width/height— explicit sizes.auto(the default) lets block elements fill their container's width and shrink-wrap their height.min-width/min-height— a floor the box cannot go below.max-width/max-height— a ceiling.max-width: 100%is the classic guard that keeps images and cards from overflowing small screens.
Percentages on width are relative to the containing block's width. Percentages on height only work if the parent has a resolved height — otherwise they compute to auto. That single rule explains most "my height: 100% does nothing" bugs.
Padding: Space Inside
Padding adds breathing room between the content and the border, and it carries the element's background.
.card {
padding: 24px; /* all four sides */
padding: 16px 24px; /* block (top/bottom) | inline (left/right) */
padding: 8px 16px 12px; /* top | left-right | bottom */
padding: 8px 16px 12px 4px;/* top | right | bottom | left (clockwise) */
}
Two things people forget:
- Padding cannot be negative.
- Percentage padding is relative to the container's width — even
padding-top. That quirk is the trick behind the old "aspect-ratio box" hack (useaspect-rationow instead).
Border: The Visible Edge
.box {
border: 2px solid #111; /* width | style | color */
border-bottom: 1px solid #ddd; /* one side */
border-radius: 12px; /* rounds the border box */
}
In content-box, border width counts toward the element's total size; in border-box, it eats into the content. outline looks similar but is not part of the box model — it is drawn on top and does not affect layout, which is exactly why it is the right tool for focus rings.
Margin: Space Outside
Margin separates a box from its neighbors. Unlike padding, it can be negative, and it has two special behaviors.
.block {
margin: 0 auto; /* horizontal auto = center a fixed-width block */
margin-top: -8px; /* negative margins pull neighbors closer / overlap */
}
margin: auto is how you center a block horizontally: give it a width and auto left/right margins. (Vertical auto margins do nothing in normal flow — but they do center in flex and grid.)
Margin Collapsing — The Classic Gotcha
When two vertical margins meet in normal flow, they don't add up — they collapse into the single larger value.
Collapsing happens between adjacent siblings, and between a parent and its first/last child. It is vertical only — horizontal margins never collapse — and it does not happen inside flex or grid containers. You break the collapse by putting something between the margins: padding, a border, or a new formatting context (display: flex, overflow: hidden, etc.). This is the real reason modern layouts prefer gap in flex/grid: gap never collapses, so spacing is predictable.
Block, Inline, and Inline-Block Boxes
The box model applies to every element, but display changes which parts take effect:
| Display | Respects width/height | Vertical margin/padding push layout |
|---|---|---|
block | Yes | Yes |
inline | No (sizes to content) | Padding/border render but don't move surrounding lines; margins only apply horizontally |
inline-block | Yes | Yes |
That table explains why width on a <span> "does nothing" until you make it inline-block or block.
Logical Properties (and Why They Matter Here)
Physical properties like margin-left assume left-to-right. On an Arabic (RTL) page, "left" is the wrong side. Logical properties follow the reading direction instead:
/* Physical — breaks in RTL */
margin-left: 16px;
padding-right: 8px;
/* Logical — correct in both LTR and RTL */
margin-inline-start: 16px;
padding-inline-end: 8px;
inline-start/inline-endmap to left/right in LTR and flip automatically in RTL.block-start/block-endmap to top/bottom.- Shorthands exist too:
margin-inline,padding-block,inset-inline.
For any interface that ships in more than one direction, logical properties remove a whole category of mirroring bugs.
Inspecting the Box in DevTools
Open the element inspector and look at the Computed tab's box-model diagram. It draws the exact four layers — content in the center, then padding, border, and margin — with the real pixel values. When spacing is "mysteriously" wrong, this diagram tells you in seconds whether it's padding, margin, or a collapsed margin doing it.
Common Mistakes
- Forgetting the
box-sizing: border-boxreset, then fighting overflow from added padding. - Expecting
height: 100%to work when the parent has no resolved height. - Adding vertical margins and being surprised they collapsed instead of summing.
- Using
width/heighton inline elements and wondering why nothing changes. - Reaching for
marginto space flex/grid children whengapis cleaner and collapse-free. - Using
margin-left/righton a bidirectional site instead of logicalinline-start/inline-end.
The Mental Model to Keep
The box is content → padding → border → margin, measured according to box-sizing. Set border-box globally so the number you write is the number you get. Use gap and logical properties for spacing, reach for DevTools' box diagram when something is off, and most layout mysteries disappear.