Skip to main content

Box model — what "width" actually refers to

Layouts that don't line up to the pixel, cards you laid out four across that wrap onto the next row — a lot of these break because the value you gave width is not the width you thought it was.

CSS treats every element as a rectangular box. The structure of that box is decided by the box model.

What you'll learn in this chapter​

  • The four regions that make up the box model, and what each is for
  • That width refers to the content region only by default, and how box-sizing changes that
  • How far the background gets painted, and where it stops
  • When top-and-bottom margins collapse, and how to stop them
Prerequisites

If you have written width or padding in CSS before, you're ready.

The four regions​

The box of an element is a nested structure of four regions, from the inside out.

The order from inside out is content → padding → border → margin. It's worth memorizing. The fact that padding sits inside the border and the margin sits outside it explains both the background painting range and margin collapsing later in this chapter.

RegionRoleDoes the background paint here?Relationship with other elements
ContentWhere the text or image itself livesYes—
PaddingSpace between content and borderYesInside the box, so it doesn't affect other elements
BorderThe boundary of the boxYes by defaultSets the outer edge
MarginSpace between one box and anotherNoPushes neighboring elements away

Padding and margin are both "space", but they behave differently. Padding grows the inside of the box, so the background color or image extends that far. Margin is space outside the box, so no background reaches it.

The four sides can be set individually​

padding, margin, and border all have shorthand forms that set all four sides at once, and longhand forms that set each side separately.

/* Longhand — set each side */
.card {
padding-top: 8px;
padding-right: 16px;
padding-bottom: 8px;
padding-left: 16px;
}

/* Shorthand — the number of values changes the interpretation */
.card {
padding: 8px; /* All four sides: 8px */
padding: 8px 16px; /* Top and bottom: 8px / left and right: 16px */
padding: 8px 16px 24px; /* Top: 8px / left and right: 16px / bottom: 24px */
padding: 8px 16px 24px 32px; /* Top → right → bottom → left (clockwise) */
}

The four-value shorthand is clockwise: top, right, bottom, left. In the three-value form, the left side is omitted and takes the value of the right. In the two-value form, the two values pair up as top-and-bottom and left-and-right.

What width refers to​

This is the single most commonly misunderstood point in the box model.

By default, width refers only to the content region. Padding and border are added on the outside.

.card {
width: 350px;
padding: 25px;
border: 5px solid;
}

The horizontal space this element occupies on screen is not 350px.

350px (content) + 25px×2 (padding) + 5px×2 (border) = 410px

You thought you had set the content to 350px, but you actually built a box that overshoots by 60px. If you set up a three-column grid at width: 33.3% and it wraps because of the padding, this is why.

This default behavior is called the standard box model (box-sizing: content-box).

box-sizing: border-box changes the interpretation​

Setting the box-sizing property to border-box changes what width means.

.card {
box-sizing: border-box;
width: 350px;
padding: 25px;
border: 5px solid;
}

Now the whole box fits within 350px. Padding and border eat into it, and the content region gets whatever is left.

350px (whole box) − 25px×2 (padding) − 5px×2 (border) = 290px (content)
content-box (default)border-box
What width refers toContent region onlyContent + padding + border
Adding paddingGrows the whole boxShrinks the content region
Total box widthLarger than the value you setMatches the value you set

For laying things out, border-box matches intuition better. If you say "this box is 350px", you want it to take up 350px. That's why applying it across the whole project as a reset has become the idiom.

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

The reason pseudo-elements are included is to keep ::before and ::after on the same calculation rules when they carry padding or borders. Utility frameworks like the ones covered in the Tailwind CSS Guide ship this reset by default. So using Tailwind makes border-box feel like the natural behavior — but in plain CSS, content-box is the default. Keep that in mind.

box-sizing does not include margins

Even with border-box, the margin stays outside width. What "the whole box" contains only goes up to the border; the margin is space between boxes. When widths don't add up in a horizontal layout, suspect the margin first.

How far the background gets painted​

The background-clip property decides how far the background color or image is painted. The initial value is border-box.

So by default, the background extends beyond the content region into the padding region and the border region as well. It does not extend into the margin region.

.card {
background-color: #eef;
padding: 24px; /* Background color reaches into this 24px too */
border: 8px dashed; /* You can see the background through the gaps in the dashes */
margin: 24px; /* Nothing here */
}

You won't notice with a solid border, but with dashed or dotted — or with a semi-transparent border — you can see the background through the gaps. That's the evidence that the background is painted underneath the border.

Changing the value of background-clip narrows the range.

ValueHow far the background is painted
border-box (initial)To the outer edge of the border
padding-boxTo the outer edge of the padding. Not under the border
content-boxContent region only
textClipped to the shape of the text

"Padding to create space, and the background color follows along" is used routinely in card and button design. When you use padding to grow both the hit area and the visual area of a button, the background comes with it, so nothing looks off.

Margin collapsing​

Suppose two elements stacked vertically have margin-bottom: 20px and margin-top: 30px. You'd expect 50px of space between them, but the actual gap is 30px.

This is margin collapsing. It happens only for vertical margins, never for left-and-right ones.

The three situations where it happens​

1. Between adjacent siblings

<p style="margin-bottom: 20px">Previous paragraph</p>
<p style="margin-top: 30px">Next paragraph</p>

The gap is not 20px + 30px = 50px; it is the larger of the two, 30px.

2. Between a parent and its first or last child

When the parent has no border-top and no top padding, and there is no inline content before the first child, the parent's margin-top collapses with the margin-top of its first child. The same applies at the bottom: if there is no inline content after the last child, and the parent has no height / min-height / border-bottom / padding-bottom, the parent's margin-bottom collapses with the last child's margin-bottom.

The phenomenon of "the margin you put on the child ends up outside the parent" is this.

3. An empty block

A block with no border, no padding, no inline content, no height, and no min-height collapses its own top and bottom margins together.

The sign of the values changes the result​

CombinationCollapsed value
Both positiveThe larger of the two
Both negativeThe smaller of the two (the most negative)
Positive and negative mixedThe sum of the largest positive and the most negative

For example, margin-bottom: 30px and margin-top: -10px collapse to 30 + (−10) = 20px.

How to stop collapsing​

To prevent unintended collapsing, put something between the two margins that would collapse. The four below all address situation 2 (parent and child).

  • Add even 1px of padding-top / padding-bottom to the parent
  • Add border-top / border-bottom to the parent
  • Make the parent display: flex or display: grid
  • Establish a new block formatting context on the parent (with overflow: auto, for example)

Of these, only flex / grid stops situation 1 (adjacent siblings). Padding, borders, and overflow: auto on the parent only separate the parent from its child, so they do nothing for collapsing between siblings. Situation 3 (an empty block) is stopped by any one of that block's own border, padding, inline content, height, or min-height.

Margins do not collapse inside a Flexbox or Grid container because those two layout models have their own layout rules. One reason recent layouts run into collapsing less often is that these two have become mainstream, and gap is now used for spacing. The actual patterns are covered in Flexbox layout and Grid layout.

Margins on floated elements and absolutely positioned elements don't collapse in the first place.

Common misconceptions​

"padding and border are always included in width." — Whether they are is decided by box-sizing. With the default content-box, they are not included; they are added on the outside. Only when you specify border-box do they become included. Many projects apply border-box in a reset, so it can feel like "of course it's included" — but that's a project setting, not the CSS default.

"padding moves in lockstep on all four sides and can't be set individually." — It can. Use the longhand like padding-top, or use the shorthand with two, three, or four values.

"Background color is only applied to the content region." — By default it is background-clip: border-box, so the background extends into the padding and border regions too. The only region it doesn't reach is the margin.

"Margins are always additive." — Vertical margins collapse. Horizontal margins don't, so they add up. Different behavior in different directions is a source of confusion.

"Setting box-sizing: border-box also includes margins." — It doesn't. What border-box includes stops at the border.

Exercises​

Q1. How many pixels wide does the following element take up on screen?

.box {
width: 200px;
padding: 10px 20px;
border: 2px solid;
margin: 16px;
}
Answer and explanation

Answer: 244px

There's no box-sizing, so the default content-box applies. width refers to the content region alone.

200px (content) + 20px×2 (left+right padding) + 2px×2 (border) = 244px

Margin is space outside the box, so it doesn't count toward the box's own width. It does affect the space to the next element, so if you're thinking about how much the element occupies in the layout, budget 32px for that separately.

Vertically, 10px×2 + 2px×2 = 24px is added on top of the content height.

Q2. If you add box-sizing: border-box to the .box above, how wide is the content region?

Answer and explanation

Answer: 156px

Under border-box, width refers to the whole box (content + padding + border), and the content is whatever is left.

200px − 20px×2 (left+right padding) − 2px×2 (border) = 156px

The whole box fits inside the 200px you specified.

Q3. How much space appears between the two paragraphs below?

.first { margin-bottom: 24px; }
.second { margin-top: 16px; }
<p class="first">Previous paragraph</p>
<p class="second">Next paragraph</p>
Answer and explanation

Answer: 24px

Vertical margins between adjacent siblings collapse. Both are positive, so the larger of the two — 24px — wins. It does not become 40px.

Making the parent display: flex with flex-direction: column disables collapsing, and the gap becomes 40px.

Q4. With a dashed border, the background color is visible through the gaps. Is this behavior specified?

Answer and explanation

Answer: Yes, this is specified.

The initial value of background-clip is border-box, so the background is painted out to the outer edge of the border. The border is drawn on top of the background, so with borders that have gaps like dashed or dotted, you see the background through the gaps.

If you don't want the background to show through, set background-clip: padding-box. The background stops at the outer edge of the padding and doesn't extend under the border.

Summary​

  • The box of an element is made of four nested regions, from the inside out: content → padding → border → margin
  • width refers to the content region alone by default (content-box); padding and border are added outside
  • box-sizing: border-box makes width include the padding and border. Margins are not included
  • By default the background is painted out to the padding and border regions (background-clip: border-box). It is not painted into the margin
  • Vertical margins collapse. It happens in three situations: adjacent siblings, parent with its first or last child, and an empty block
  • Padding and margin can both be set individually on each side
Related references