Boxes and positioning

Box sizing

Compare content-box with border-box and make declared widths include padding and borders for predictable component sizing.

In the last lesson we saw that width only sizes the content by default. Padding and border get added on the outside. This is box-sizing: content-box, and it’s the reason a 200px box with 20px of padding and a 5px border ends up 250px wide.

That math is annoying. If you want a card to be 200px wide, you want the visible card to be 200px, border to border. box-sizing: border-box gives you that: the declared width includes padding and border, and the browser shrinks the content area to make room.

Same box, border-box: 200px on screen. The content area inside becomes 150px.

Set it everywhere

Almost every project sets border-box globally, and I do it in every stylesheet I start. The course page does it with * { box-sizing: border-box }. Here is a slightly more flexible version:

html {
  box-sizing: border-box;
}

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

The root gets border-box, and everything else inherits it. The difference from the simple * rule is what happens when one component needs content-box for some reason: set it on the component, and its children follow, because they inherit instead of each having a hard-coded value. It’s a small thing, but it’s the version I use.

What it does and doesn’t change

border-box moves padding and border inside the declared width. Margin stays outside. A 200px border-box card with 1rem of margin still pushes its neighbors 1rem away.

If padding and border add up to more than the declared width, the content area can’t go negative. It stops at zero, and the box grows to fit its own padding and border. So the declared size is a minimum in that case, not an exact value.

And box-sizing does nothing about overflow. A box that is too small for its text still overflows, whichever model you use. For that you need flexible widths, wrapping, or the overflow properties we’ll cover later.

Why width: 100% used to break

Here’s the classic case that made everyone adopt border-box. Form inputs, width: 100%, plus a bit of padding. With content-box the input is 100% of the parent plus the padding, so it sticks out past the right edge. With border-box it fits exactly.

Try it on the course page. Add two text inputs inside a card, both with width: 100%, padding: 0.75rem, and a 1px border. In DevTools, switch box-sizing between the two values on one of them. Measure the parent and the input in the Layout diagram rather than eyeballing it. The content-box one is wider than its parent by exactly the padding and border.

Lesson completed