Type something to search...
The CSS Box Model Explained: Content, Padding, Border, and Margin

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

Every element you put on a web page, from a paragraph to a button to an image, is drawn as a rectangle. The rules that decide how big that rectangle is, how much breathing room it gets, and how it sits next to its neighbors are called the CSS box model. It's one of the first concepts people learn in CSS, and also one of the most common sources of confusion later: widths that come out larger than expected, gaps that appear from nowhere, and margins that seem to vanish.

This guide breaks down each layer of the box, explains how the browser calculates an element's size, and covers the behaviors that trip people up, including box-sizing, margin collapsing, and the difference between block and inline boxes.

The Four Layers of the Box

From the inside out, every box has four areas:

  1. Content: where text, images, or child elements live. Its size is set by width and height (or determined by the content itself).
  2. Padding: transparent space between the content and the border. It takes on the element's background color.
  3. Border: a line (or no line) wrapping the padding. Controlled by border-width, border-style, and border-color.
  4. Margin: space outside the border that separates the element from its neighbors. It's always transparent.

Here's a simple element that uses all four:

<div class="box">Hello, box model</div>
.box {
  width: 300px;
  padding: 20px;
  border: 5px solid #38bdf8;
  margin: 30px;
  background: #e0f2fe;
}

The background color fills the content and padding areas and extends under the border. The margin stays transparent, showing whatever is behind the element.

How Width Is Calculated: content-box

Here's the part that surprises beginners. With default settings, the width you set applies only to the content area. Padding and border are added on top.

For the .box above:

LayerLeftContentRightTotal
Content300px300px
Padding20px20px40px
Border5px5px10px
Rendered width350px
Margin30px30px60px
Space taken up410px

So a box you declared as 300px wide actually renders 350px wide on screen and occupies 410px of horizontal space including margins. This default behavior is called box-sizing: content-box.

It becomes a real problem with percentage widths:

.column {
  width: 50%;
  padding: 1rem;
  border: 1px solid #cbd5e1;
}

Two of these side by side don't fit, because each is 50% plus 2rem of padding plus 2px of border. The second column wraps onto a new line.

The Fix: box-sizing: border-box

With box-sizing: border-box, the width and height you set include the content, padding, and border. The content area shrinks to make room.

.box {
  box-sizing: border-box;
  width: 300px;
  padding: 20px;
  border: 5px solid #38bdf8;
}

Now the rendered box is exactly 300px wide. The content area is 300 - 40 - 10 = 250px. Margins are still added outside, since they're not part of the box's own size.

Almost every modern project applies border-box globally:

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

An alternative pattern sets it on the root and lets it inherit, which makes it easier for a specific component (like a third-party widget) to opt back into content-box:

html {
  box-sizing: border-box;
}

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

Either is fine. The important thing is to pick one and apply it at the top of your stylesheet, so every width in your project means the same thing.

Content: Sizing the Inner Box

The content area's size can come from explicit properties or from the content itself.

Explicit sizes

width, height, min-width, max-width, min-height, and max-height constrain the box. A common, robust pattern for containers:

.container {
  width: 100%;
  max-width: 72rem;
  margin-inline: auto;
}

Intrinsic sizes

CSS also has keywords that size a box based on its content:

  • min-content: the narrowest the box can be without overflowing (roughly, the longest word).
  • max-content: the width the content would take if it never wrapped.
  • fit-content: uses the available space, but never more than max-content and never less than min-content.
.tag {
  width: fit-content;
  padding: 0.25rem 0.75rem;
  border-radius: 999px;
  background: #ede9fe;
}

Logical properties

Instead of width and height, you can use inline-size and block-size, which adapt to the writing mode. In English (horizontal, left-to-right) they map to width and height. In vertical writing modes, they swap. The same logic applies to padding, border, and margin: padding-inline, margin-block-start, border-inline-end, and so on. They're supported in all current major browsers and are a good default for new code.

Padding: Space Inside

Padding adds space between the content and the border. It accepts one to four values, clockwise from the top:

.button {
  padding: 0.75rem; /* all sides */
  padding: 0.75rem 1.5rem; /* top/bottom, left/right */
  padding: 0.5rem 1rem 0.75rem; /* top, left/right, bottom */
  padding: 0.5rem 1rem 0.75rem 2rem; /* top, right, bottom, left */
}

A few things to know:

  • Padding can't be negative. Margins can.
  • Percentage padding is relative to the containing block's inline size (width), even for padding-top and padding-bottom. That quirk was the basis of the old "padding hack" for fixed aspect-ratio boxes. Today you should use aspect-ratio instead:
.video-frame {
  width: 100%;
  aspect-ratio: 16 / 9;
}
  • Padding is part of the clickable area. Increasing padding on links and buttons is the easiest way to make touch targets bigger without changing the visual design much.

Border: The Edge of the Box

The border sits between padding and margin. The shorthand takes width, style, and color:

.card {
  border: 1px solid #e2e8f0;
  border-radius: 12px;
}

A border with no style won't render. border: 2px #000 shows nothing because border-style defaults to none. It's a classic "why isn't my border showing?" bug.

Outlines and box shadows don't affect layout

If you want a visual edge without changing the element's size, reach for outline or box-shadow. Neither takes up space in the box model:

.input:focus-visible {
  outline: 2px solid #38bdf8;
  outline-offset: 2px;
}

.card {
  box-shadow: 0 0 0 1px #e2e8f0; /* a "border" that doesn't add size */
}

This is particularly useful for hover and focus states. Adding a border on hover changes the element's dimensions and causes the layout to shift; an outline or shadow doesn't.

Margin: Space Outside

Margins push the element away from its neighbors. They use the same one-to-four-value syntax as padding, but they have some unique behaviors.

Negative margins

Margins can be negative, pulling the element toward or over its neighbors:

.full-bleed {
  margin-inline: -1rem; /* extend past a parent's 1rem padding */
}

Auto margins

margin: auto distributes available space. On a block with a set width, margin-inline: auto centers it horizontally. In flex and grid layouts, auto margins absorb free space in any direction, which makes them useful for pushing items apart.

Percentage margins

Like padding, percentage margins are always relative to the containing block's width, including top and bottom margins.

Margin Collapsing

This is the behavior that causes the most confusion. In normal block layout, vertical margins between adjacent blocks collapse into a single margin equal to the larger of the two.

<h2 class="heading">Section title</h2>
<p class="lead">Intro paragraph.</p>
.heading {
  margin-bottom: 24px;
}
.lead {
  margin-top: 16px;
}

You might expect 40px of space between them. You get 24px, the larger of the two. Horizontal margins never collapse.

Parent and child collapsing

Margins can also collapse between a parent and its first or last child, if nothing separates them (no padding, border, or inline content):

<section class="hero">
  <h1 class="hero-title">Welcome</h1>
</section>
.hero {
  background: #0f172a;
}
.hero-title {
  margin-top: 48px;
}

Instead of pushing the heading down inside the dark hero, the 48px margin "escapes" and appears above the hero, pushing the whole section down. The background doesn't extend into that space.

How to prevent collapsing

Any of these stops a parent and child's margins from collapsing:

  • Add padding or border to the parent.
  • Make the parent a flex or grid container (margins never collapse inside flex or grid layouts).
  • Make the parent establish a new block formatting context with display: flow-root.
.hero {
  display: flow-root;
  background: #0f172a;
}

display: flow-root is the cleanest option when you want normal block layout without collapsing. It's supported in all modern browsers.

A modern approach: spacing with gap

Many teams sidestep collapsing entirely by avoiding vertical margins on components and letting the parent control spacing with gap:

.stack {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

The spacing is predictable, lives in one place, and never collapses.

Block vs. Inline Boxes

The box model applies fully to block boxes, but inline boxes behave differently:

  • width and height are ignored on non-replaced inline elements like span and a.
  • Horizontal padding, borders, and margins push neighbors apart as you'd expect.
  • Vertical padding and borders are drawn, but they don't affect the line height, so they can overlap lines above and below.
  • Vertical margins have no effect at all.
.highlight {
  padding: 0.5rem;
  background: #fef3c7;
}

On an inline span, the yellow background extends vertically, but the text lines don't move apart, which can look broken. If you need the box model to fully apply, use display: inline-block (still flows with text) or display: block.

Replaced elements such as img and video are inline by default but do respect width and height. They also sit on the text baseline, which leaves a small gap underneath images inside containers. display: block or vertical-align: middle removes it.

Inspecting the Box Model in DevTools

Every browser's DevTools has a box model diagram. In Chrome or Edge, select an element, open the Computed tab, and you'll see nested rectangles showing the content size, padding, border, and margin, each labeled with its value. Hovering over an element in the Elements panel highlights the areas in different colors on the page: content in blue, padding in green, margin in orange. It's the fastest way to understand why something is bigger or further away than you expected.

Common Pitfalls

Forgetting box-sizing. If widths are coming out larger than declared, check whether border-box is applied.

Unexpected space from margin collapsing. If a margin appears outside a parent instead of inside, the parent and child margins are collapsing. Use display: flow-root or padding.

Borders that don't render. Always include a border-style.

Layout shift on hover. Adding or thickening a border changes the element's size. Use outline or an inset box-shadow instead, or reserve the space with a transparent border in the default state.

Percentage vertical padding. It's relative to width, not height. Use aspect-ratio for proportional boxes.

Conclusion

The CSS box model is four nested layers: content, padding, border, and margin. By default, width only measures the content, which is why most projects switch to box-sizing: border-box so declared sizes include padding and border. Margins are the odd one out: they can be negative, can be auto, and collapse vertically in normal flow unless something separates them.

Once you can picture those four rectangles around every element, and know how to see them in DevTools, most layout mysteries turn into simple arithmetic. That's the real value of understanding the box model: it makes CSS predictable.

Tags :
Share :

Related Posts

A Complete Guide to CSS Container Queries

A Complete Guide to CSS Container Queries

For more than a decade, responsive design meant one thing: media queries. You asked the browser how wide the viewport was and adjusted your layout ac

Continue Reading
A Comprehensive Guide to Installing Next.js

A Comprehensive Guide to Installing Next.js

Next.js has emerged as a powerful framework for building React applications, offering features like server-side rendering, static site generation, an

Continue Reading
Advanced CSS with clamp(), min(), and max(): Simplifying Dynamic Styling

Advanced CSS with clamp(), min(), and max(): Simplifying Dynamic Styling

CSS has evolved significantly, and modern tools like clamp(), min(), and max() are powerful game-changers in dynamic styling. If you’ve struggl

Continue Reading