TH The Sass Way
CSS Fundamentals

The CSS Box Model: Margin, Border, Padding, and Content

The CSS Box Model: Margin, Border, Padding, and Content
tldrThe CSS box model describes every element as four nested layers: content in the center, padding around it, a border around the padding, and margin outside everything. Padding and border add to an element's size (unless you set box-sizing: border-box), while margin is transparent space that separates the box from its neighbors.

The CSS Box Model in One Sentence

Every element on a web page is a rectangular box, and the CSS box model describes how the browser calculates that box's total size from four layers: the content, the padding around it, the border around that, and the margin outside everything. Understand those four layers and one property (box-sizing), and most "why is this element the wrong size?" mysteries disappear.

Here is the model from the inside out:

Layer What it is Grows the box? Has a background?
Content The text, image, or child elements Set by width/height Yes
Padding Clear space inside the border Yes Yes (element's bg shows through)
Border The line around the padding Yes It is the visible edge
Margin Clear space outside the border Pushes neighbors away No — always transparent

The order never changes: content sits in the middle, padding wraps it, border wraps the padding, and margin is the empty moat on the outside. A background color or image fills the content and padding, stops at the border, and never bleeds into the margin.

The Four Layers, Explained

Content

The content box holds whatever the element contains. Its dimensions come from width and height (or, if you set neither, from the content itself and the element's display type). For a block element with no explicit width, the content box stretches to fill its parent.

Padding

Padding is breathing room inside the box. Because the element's background extends through the padding, it's what you reach for when you want space between text and the edge of a button or card without the background stopping short.

.button {
  padding: 12px 20px; /* 12px top/bottom, 20px left/right */
}

Padding accepts one to four values (top, right, bottom, left — clockwise), or you can target one side with padding-top, padding-inline, and friends. Padding can never be negative.

Border

The border draws a visible line between padding and margin. Its shorthand takes a width, a style, and a color:

.card {
  border: 2px solid #d0d0d0;
}

A border only renders if you give it a style (solid, dashed, dotted, etc.). border-width alone does nothing without a style. Border width counts toward the box's rendered size, which matters for the box-sizing discussion below.

Margin

Margin is transparent space outside the border that pushes other elements away. Unlike padding, margin can be negative (margin-top: -10px pulls an element upward), and it does not carry the element's background.

Margin also has two behaviors that trip people up: margin: 0 auto centers a block element horizontally, and vertical margins collapse — a topic worth its own section below.

Margin vs. Padding: The Difference That Actually Matters

Both add space, so which do you use? The reliable test:

Question Margin Padding
Inside or outside the border? Outside Inside
Shows the element's background? No Yes
Can be negative? Yes No
Counts as clickable area? No Yes
Collapses with neighbors? Yes (vertical) Never

A concrete example: to make a link's entire padded area clickable and give it a hover background, pad it. To space that link away from the next one, add margin. If you had used margin for the interior gap, the background would stop at the text and the extra space wouldn't register clicks.

For a full breakdown of the length units you'll plug into these properties — when to use px, rem, em, or % — see our guide to CSS units.

box-sizing: The Single Most Useful Line of CSS

Here's the classic surprise. You set a width of 300px, add padding and a border, and the element renders wider than 300px:

.box {
  width: 300px;
  padding: 20px;
  border: 5px solid black;
  /* Rendered width = 300 + 20 + 20 + 5 + 5 = 350px */
}

By default (box-sizing: content-box), width sizes only the content box. Padding and border are added on top, so your 300px box occupies 350px. Multiply that across a grid and layouts overflow their containers.

The fix is box-sizing: border-box, which makes width include padding and border:

.box {
  box-sizing: border-box;
  width: 300px;
  padding: 20px;
  border: 5px solid black;
  /* Rendered width = 300px. Content shrinks to 250px to make room. */
}

Now the box is exactly the width you asked for, and padding and border eat into that width instead of stacking onto it. This is so much more predictable that nearly every modern codebase applies it globally:

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

Drop that at the top of your stylesheet and width starts meaning what you expect. border-box is supported in every browser in use today, so there's no compatibility reason to avoid it.

content-box (default) border-box (recommended)
width applies to Content only Content + padding + border
A 300px box with 20px padding + 5px border renders at 350px 300px
Adding padding later Grows the box Shrinks the content
Best for Legacy quirks Predictable layouts

Note that margin is never included in either mode — it always sits outside the declared width. A 300px border-box element with 10px of horizontal margin still occupies 320px of horizontal space in its container.

Margin Collapsing: Why Your Vertical Spacing Looks Wrong

Vertical (block-direction) margins between elements don't add up the way you'd expect. Instead, the larger of two adjacent margins wins and the smaller is absorbed. This is called margin collapsing.

.top    { margin-bottom: 30px; }
.bottom { margin-top: 20px; }
/* Gap between them is 30px, NOT 50px */

The browser uses the larger margin (30px) and discards the overlap. Collapsing happens in three situations:

Key rules to remember:

If margin collapsing is fighting you, common fixes are switching the container to display: flex and using the gap property, adding a single padding or border to the parent, or simply applying margin in one direction only (many developers use margin-top everywhere, or margin-bottom everywhere, but not both).

Inline Elements Play by Different Rules

The box model applies to every element, but inline elements (like <span> and <a> by default) treat it selectively:

If you need full box-model control on an inline element — a link styled as a button, say — promote it with display: inline-block (keeps it in the text flow but respects width/height) or display: block. This is exactly what button-style links do.

Debugging With the Box Model

Every browser's DevTools shows a live box-model diagram. Right-click an element, choose Inspect, and look at the Computed tab (Chrome, Edge, Firefox) for a color-coded rectangle: content in blue, padding green, border yellow, margin orange. Hover each layer and the browser highlights it on the page. When an element is "too big" or spacing looks off, this diagram tells you instantly which layer is responsible — usually a padding you forgot or a margin that collapsed.

A quick visual-debugging trick during layout work:

* {
  outline: 1px solid rgba(255, 0, 0, 0.3);
}

outline is deliberately used here instead of border because — unlike border — outline doesn't affect the box model or layout. It draws on top without shifting anything, so you can see every box's edges without changing their sizes. Remove it before shipping.

Putting It Together

The box model is the foundation the rest of CSS layout stands on. Once the four layers and box-sizing: border-box are second nature, the properties that place those boxes on the page — Flexbox, Grid, and positioning — become far easier to reason about, because you already know exactly how big each box is and where its edges fall.

From here, two natural next steps: if you're still building your base, our beginner's guide to CSS sets the broader context, and once you're sizing boxes confidently, learning how to center a div puts margins, padding, and the box model to work in the layout task everyone eventually needs.

A short checklist to keep the box model working for you:

FAQ

What is the CSS box model?

The CSS box model is the way browsers calculate the size and spacing of every element by treating it as four nested layers: content, padding, border, and margin. Content holds the element's text or children, padding is space inside the border, the border is the visible edge, and margin is transparent space pushing neighboring elements away.

What is the difference between margin and padding?

Padding is space inside the border, so it shares the element's background, counts as clickable area, and can't be negative. Margin is space outside the border, so it's always transparent, separates the element from its neighbors, can be negative, and collapses with adjacent vertical margins. Use padding for interior space and margin for gaps between elements.

What does box-sizing: border-box do?

By default, an element's width applies only to its content, so padding and border are added on top and make the box larger than expected. Setting box-sizing: border-box makes width include padding and border, so the rendered box matches the width you declared and the content shrinks to fit. It's widely applied globally for predictable layouts.

Does margin count toward an element's width?

No. Margin is never included in an element's declared width in either box-sizing mode. A 300px border-box element with 10px of horizontal margin on each side still occupies 320px of space in its container. Only padding and border can be folded into the width, and only when box-sizing is set to border-box.

What is margin collapsing in CSS?

Margin collapsing is when two adjacent vertical margins combine into a single margin equal to the larger of the two, rather than adding together. It happens between stacked siblings, between a parent and its first or last child, and within empty blocks. Only vertical margins collapse; padding, borders, and horizontal margins never do.

Why is my element bigger than the width I set?

The usual cause is the default box-sizing: content-box, where padding and border are added on top of the width you set. A 300px box with 20px padding and a 5px border renders at 350px. Fix it by applying box-sizing: border-box, which folds padding and border into the declared width instead of stacking them on.