You write width: 200px, add a little padding and a border, and the box on screen comes out 250 pixels wide. Then two boxes that should sit side by side drop onto separate lines. Nothing is broken: CSS is following a rule called the box model. Once you see it, a whole category of "why is this too wide?" bugs disappears, and one line of CSS makes most of them go away for good.

Every element is a box

When a browser draws a web page, it treats every element (a paragraph, a button, an image, a <div>) as a rectangle. CSS (Cascading Style Sheets, the language that controls how HTML looks) lets you size that rectangle, and it's built from four layers, nested like the rings of an onion:

margin · empty space outside, pushes neighbours away
border · the visible edge line
padding · breathing room inside the edge
content · the text or image itself
From the inside out: content → padding → border → margin.

Here is a typical rule that sets all four. A px is a CSS pixel, the standard unit for sizes on screen:

.card {
  width: 200px;
  padding: 20px;               /* on all four sides */
  border: 5px solid orange;    /* thickness, style, colour */
  margin: 20px;                /* on all four sides */
}

So how wide is the card? Most people guess 200px. The browser says 250px.

Why 200px turns into 250px

By default, CSS applies width to the content area only. Padding and border are then added on both sides, left and right:

  200   content
+  40   padding  (20 left + 20 right)
+  10   border   ( 5 left +  5 right)
= 250px          the box you can see

The margin isn't in that 250, because margin is invisible. But it still takes up room: the card needs 250 + 20 + 20 = 290px of horizontal space before the next thing can sit beside it.

This default behaviour has a name: box-sizing: content-box. The setting box-sizing decides which layer the width measures, and almost every element starts with content-box (a few form controls such as buttons are exceptions). Play with the sliders and watch the numbers. Then flip the switch at the top.

Box model playground

contentpaddingbordermargin

The readout's last line, browser measured, isn't calculated by this page's maths. It asks the browser how wide it actually drew the box (a value JavaScript calls offsetWidth), so you can see the formula and the real result agree.

Where this bites: things that should fit, don't

An extra 50 pixels might sound harmless. It stops being harmless the moment you size things relative to their container. Two classic cases:

Try both. The dashed outline is the parent element, the container the boxes are supposed to fit inside.

Layout lab

parent

Notice what happens at padding 0: everything fits again, because there's nothing to add. That's why this bug shows up late. A layout works fine until someone adds a bit of padding to make it look nicer.

A box with no width set is fine. If you leave width alone, a block element like a <div> or <p> automatically fills its container, and its padding and border fit inside that space. The surprise only happens when you set an explicit width (or height) on something that also has padding or border.

The fix: box-sizing: border-box

With box-sizing: border-box, width measures from the outside of the border instead. The box is exactly as wide as you said, and the browser squeezes the padding and border inside that width, making the content area smaller to compensate:

  200px   width you asked for = the box you see
−  40     padding
−  10     border
= 150px   left for the content

Most developers find this far easier to think about: "this card is 200 pixels wide" means what it says. It's so popular that nearly every modern project starts its stylesheet with this rule, which switches every element on the page over:

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

The * is the universal selector: it matches every element. ::before and ::after are pseudo-elements, little extra boxes CSS can generate before or after an element's content; they aren't matched by * alone, so they're listed separately. Popular CSS frameworks such as Bootstrap and Tailwind include this rule for you.

Two things border-box does not change:

Shorthand: setting sides separately

So far every side got the same value. padding and margin also take two, three or four values, and the order trips people up:

padding: 10px;                 /* all four sides */
padding: 10px 20px;            /* top+bottom 10, left+right 20 */
padding: 10px 20px 30px;       /* top 10, left+right 20, bottom 30 */
padding: 10px 20px 30px 40px;  /* top, right, bottom, left */

The four-value version goes clockwise from the top: top, right, bottom, left. You can also target one side with padding-left, margin-top and so on. For width, only the left and right values count, so padding: 10px 20px adds 40px to a content-box element's width, not 20.

One handy margin trick: margin: 0 auto on a block element that has a width tells the browser to split the leftover horizontal space evenly between the left and right margins, which centres the box in its container.

Margins between stacked boxes can overlap. When one ordinary block sits on top of another, their vertical margins don't add up: a 20px bottom margin above a 30px top margin gives a 30px gap, not 50px. The larger one wins. This is called margin collapsing, and it only happens vertically, never left and right (and not between items inside a flexbox or grid layout).

See it in your own browser

You don't have to do the sums yourself. Right-click any element on any web page, choose Inspect, and the browser's developer tools open. In the styles area (Chrome calls the tab Computed; Firefox shows it under Layout) there's a diagram of nested rectangles, just like the one at the top of this page, labelled with the element's real content size, padding, border and margin. Hovering over it highlights each layer on the page in a different colour. When a layout looks wrong, that diagram is usually the fastest way to find the extra pixels.

Check yourself

Assume the default content-box unless the question says otherwise.

How wide is the visible box?

width: 300px; padding: 10px; border: 1px solid;

300 content + 10 + 10 padding + 1 + 1 border = 322px. Padding and border are added on both sides.

Same rule, but with box-sizing: border-box. How wide is the content area?

box-sizing: border-box;
width: 300px; padding: 10px; border: 1px solid;

The box is exactly 300px. Padding (20) and border (2) are taken out of it: 300 − 22 = 278px left for content.

How wide is the visible box (border included)?

width: 100px; margin: 20px;

Margin is transparent space outside the border. It isn't part of the box's size, though the box does need 140px of room in total.

How much padding is on the left side?

padding: 10px 20px;

With two values, the first is top and bottom, the second is left and right. So left and right each get 20px.

The short version

Next time something is a few pixels too wide, don't nudge numbers until it fits. Add up the layers, or switch to border-box and let the width mean what it says.