Skip to content

Lesson 4 of 9 · 16m

The Box Model Nobody Explains Properly

Content, padding, border, margin — and the one `box-sizing` rule that ends the arithmetic forever.

Every layout bug you have ever fought comes back to one thing: not knowing what width actually means. By default, width: 300px sets the content width — then padding and border are added on top. A "300px column" with 16px padding and a 2px border is really 336px wide. This is why your columns overflow their parents.

The mental picture

+--- margin (outside, transparent, collapses) ---+
|  +--- border ---------------------------------+
|  |  +--- padding (inside, keeps background) --+
|  |  |  content: text, images                 |
|  |  +-----------------------------------------+
|  +--------------------------------------------+
+------------------------------------------------+

The one rule that fixes it

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

With border-box, width: 300px means the element including padding and border is 300px. Every professional codebase sets this at the top of the stylesheet. If yours does not, every width you write is a riddle.

Margins collapse — really

When two vertical margins meet, they do not add — they collapse to the larger one. A <p> with margin-bottom: 20px followed by another with margin-top: 30px produces 30px of space, not 50. This confuses everyone once. It is not a bug; it is how document flow spacing was designed.

Try it yourself — the arithmetic, live

const declared = 300, padding = 16, border = 2;
const contentBox = declared + (padding * 2) + (border * 2);
console.log("content-box width:", contentBox, "px (surprise!)");
console.log("border-box width:", declared, "px (what you meant)");

Debugging habit

When an element is the wrong size, open DevTools and look at the computed box model — the four nested numbers (content, padding, border, margin) are printed right there. Guessing is slow; the numbers are free.