CSS Box Model

Understand how every HTML element is rendered as a rectangular box made of content, padding, border, and margin, and how box-sizing changes the way width and height are calculated.

Every single element on a web page — a paragraph, a button, a div, an image — is rendered by the browser as a rectangular box. This is not a metaphor; it is literally how the CSS rendering engine works. Before you can reliably control spacing, alignment, or layout, you need a precise mental model of what that box is made of. That model is called the CSS Box Model, and it is arguably the single most important concept in all of CSS. Nearly every layout bug a beginner runs into — 'why is there a gap here', 'why did my element grow past its container', 'why won't this width work' — traces back to a misunderstanding of the box model.

The Four Layers of a Box

Every box is built from four concentric layers, from the inside out: content, padding, border, and margin. The content area holds the actual text, image, or child elements. Padding is the transparent cushion of space between the content and the border — it is still 'inside' the element and typically inherits the element's background color. The border is a visible (or invisible) line that wraps around the padding and content. And margin is the transparent space outside the border that pushes other elements away.

It helps to think of a physical analogy: content is a photograph, padding is the white mat around it, border is the picture frame, and margin is the empty wall space between this framed picture and the next one hanging beside it. Each layer can be sized and colored independently using properties like padding, border, and margin — each of which further breaks down into -top, -right, -bottom, and -left variants, or shorthand forms.

• content — the actual text/media; sized by width and height • padding — inner spacing, part of the element's own background • border — a visible line around the padding; has width, style, and color • margin — outer spacing; always transparent, used to separate elements

box-sizing: content-box vs border-box

This is where most beginners get tripped up. By default, the CSS box-sizing property is set to content-box. Under content-box, the width and height properties you set apply ONLY to the content area — padding and border are added ON TOP of that width. So if you write width: 200px; padding: 20px; border: 5px solid black;, the element's actual rendered width is 200 + 20 + 20 + 5 + 5 = 250px, not 200px. This catches people off guard constantly: you set a width, add some padding to make things look nicer, and suddenly your element is wider than you expected and breaks your layout grid.

The fix is box-sizing: border-box. Under border-box, the width and height you specify include the padding and border — the browser shrinks the content area to make room for them instead of growing the total box. So width: 200px; padding: 20px; border: 5px solid black; box-sizing: border-box; produces an element that is exactly 200px wide, period, with the content area automatically reduced to 150px to accommodate the 40px of padding and 10px of border.

Because border-box is so much more predictable and matches how most designers think about sizing ('I want this box to be exactly 200px wide, full stop'), it has become an industry-standard reset. Most production stylesheets start with a rule that applies border-box to every element on the page.

• content-box (default): width/height = content only; padding & border ADD to the total size • border-box: width/height = content + padding + border, all included; the total size never changes when you tweak padding • Common reset: *, *::before, *::after { box-sizing: border-box; } applied globally at the top of a stylesheet

Box Model Properties

padding, border, and margin each accept 1 to 4 values (top/right/bottom/left, clockwise from top) border is shorthand for border-width, border-style, and border-color box-sizing is usually set once globally, not per-element

.box {
  width: 200px;
  height: 100px;
  padding: 16px;
  border: 2px solid #333;
  margin: 24px;
  box-sizing: border-box;
}

Code Examples

Both rules request a 200px width, but content-box adds padding and border on top of that number while border-box absorbs them inside it, so the two boxes end up visually 50px apart in total width even though 'width: 200px' appears in both. Expected result: .content-box renders at 250px wide; .border-box renders at exactly 200px wide.

This is one of the most common lines in real-world CSS resets. Applying border-box to every element (including pseudo-elements) makes width and padding behave predictably across the whole site, so developers rarely have to think about box-sizing again after setting this once.

Padding is filled with the element's own background color (#f0f4ff bleeds into the padding here), while margin is always invisible/transparent and simply creates distance to the next element on the page.

.content-box {
  box-sizing: content-box; /* default */
  width: 200px;
  padding: 20px;
  border: 5px solid crimson;
  /* rendered width = 200 + 40 + 10 = 250px */
}

.border-box {
  box-sizing: border-box;
  width: 200px;
  padding: 20px;
  border: 5px solid teal;
  /* rendered width = exactly 200px; content shrinks to 150px */
}
*,
*::before,
*::after {
  box-sizing: border-box;
}
.card {
  background: #f0f4ff;
  padding: 20px;      /* space INSIDE, same background */
  border: 1px solid #ccd;
  margin-bottom: 32px; /* space OUTSIDE, always transparent */
}

The Box Model, Layer by Layer

Four nested layers, from innermost to outermost: content, padding, border, margin. width/height only ever target the content box unless box-sizing: border-box is set.

+-------------------------------+
|            MARGIN             |
|  +--------------------------+  |
|  |         BORDER           |  |
|  |  +--------------------+  |  |
|  |  |     PADDING        |  |  |
|  |  |  +--------------+  |  |  |
|  |  |  |   CONTENT    |  |  |  |
|  |  |  +--------------+  |  |  |
|  |  +--------------------+  |  |
|  +--------------------------+  |
+-------------------------------+

Important Rules

width and height style the content box by default (content-box); use border-box to include padding and border in that number instead.

padding always shares the element's background color; margin is always transparent.

border sits exactly between padding and margin, and its width counts toward the element's total footprint under content-box.

Setting box-sizing: border-box globally at the top of a stylesheet is standard practice and prevents most sizing surprises.

Why this matters on real projects

Building a 3-column layout where each column should be exactly one-third of its container is a daily task. If box-sizing is left at the default content-box and any column has padding or a border, the columns will not add up to 100% and will wrap or overflow unpredictably. Every serious CSS framework and reset (Bootstrap, Tailwind's preflight, normalize.css derivatives) sets border-box globally for exactly this reason — it is the first line of defense against layout bugs..box { width: 300px; padding: 20px; border: 10px solid black; }.box { box-sizing: border-box; width: 300px; padding: 20px; border: 10px solid black; }

Without border-box, this element actually renders at 300 + 40 + 20 = 360px wide — 60px wider than intended — which silently breaks any grid or alignment that assumed the box was exactly 300px.

[Predict the Output] Given the following CSS, what is the actual rendered width of the element? .box { box-sizing: content-box; width: 100px; padding: 10px; border: 5px solid black; margin: 20px; } .box { box-sizing: content-box; width: 100px; padding: 10px; border: 5px solid black; margin: 20px; } A. 100px B. 120px C. 130px D. 170px

C. 130px — Under content-box, width applies only to content. Total rendered box width = 100 (content) + 10+10 (left/right padding) + 5+5 (left/right border) = 130px. Margin (20px each side = 40px) adds outer spacing but does not count toward the element's own width, so it's excluded from the box's own width figure.

Create a.card class that is exactly 240px wide no matter how much padding or border you add. Give it 24px of padding, a 3px solid border, and confirm the rendered width stays 240px..card { box-sizing: border-box; width: 240px; padding: 24px; border: 3px solid #333; }

You need box-sizing: border-box on the element before width will 'stay put' when padding/border are added.