Understanding the Box Model

▶ Try It Yourself

Every HTML element rendered on a page is treated by the browser as a rectangular box. The CSS Box Model defines how that box is structured — four nested layers that control an element’s total size and spacing. Understanding the box model is the single most foundational concept for mastering CSS layout. In this lesson you will learn all four layers, how they interact, and how to visualise them using browser DevTools.

The Four Layers of the Box Model

From innermost to outermost, every box is made of:

Layer CSS Property Description
Content width / height Where text, images, or child elements live
Padding padding Transparent space inside the border, around the content
Border border A visible (or invisible) line wrapping padding + content
Margin margin Transparent space outside the border, between elements

content-box vs border-box

box-sizing What width includes Computed Total Width
content-box (default) Content only width + padding-left + padding-right + border-left + border-right
border-box Content + padding + border Exactly the value of width — no surprises

Visualising the Box in DevTools

Browser Open DevTools Box Model Location
Chrome / Edge F12 or Ctrl+Shift+I Elements → Computed tab → Box Model diagram
Firefox F12 Inspector → Computed → Box Model section
Safari Cmd+Opt+I Elements → Computed → Box section
Note: In the browser’s box model diagram, the four layers appear as nested coloured rectangles — blue for content, green for padding, tan for border, orange for margin. Hover over the numbers to see computed values and click to edit them live.
Tip: Add outline: 2px solid red to any element during development to visualise its bounds. Unlike border, an outline never affects layout or the box model — it is purely visual and perfect for debugging.
Warning: The browser default box-sizing: content-box means a width: 300px element with padding: 20px and border: 2px actually renders at 344px wide. Always apply box-sizing: border-box globally to make sizing intuitive and predictable.

Basic Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Box Model Demo</title>
  <style>
    /* Global border-box reset — add to every project */
    *, *::before, *::after {
      box-sizing: border-box;
    }

    body {
      font-family: system-ui, sans-serif;
      padding: 32px;
      background: #f8fafc;
    }

    /* content-box comparison */
    .box-content {
      box-sizing: content-box;      /* default — padding ADDS to width */
      width: 300px;
      padding: 24px;
      border: 3px solid #ef4444;
      margin: 0 0 24px;
      background: #fee2e2;
      color: #7f1d1d;
      font-size: 0.875rem;
    }

    /* border-box — padding INCLUDED in width */
    .box-border {
      box-sizing: border-box;       /* total = exactly 300px */
      width: 300px;
      padding: 24px;
      border: 3px solid #4f46e5;
      margin: 0 0 24px;
      background: #ede9fe;
      color: #1e1b4b;
      font-size: 0.875rem;
      border-radius: 8px;
    }

    /* Debug outline — no layout impact */
    .box-border {
      outline: 2px dashed #94a3b8;
      outline-offset: 8px;
    }
  </style>
</head>
<body>

  <div class="box-content">
    <strong>content-box (default)</strong><br>
    width: 300px + padding: 24px + border: 3px<br>
    <em>Actual rendered width = 354px</em>
  </div>

  <div class="box-border">
    <strong>border-box</strong><br>
    width: 300px (padding + border included)<br>
    <em>Actual rendered width = exactly 300px</em>
  </div>

</body>
</html>

How It Works

Step 1 — content-box Adds Padding and Border on Top

With the default box-sizing: content-box, setting width: 300px reserves 300px for content only. Padding (24px × 2 = 48px) and border (3px × 2 = 6px) are added on top, making the total rendered width 354px — often breaking layouts.

Step 2 — border-box Absorbs Padding and Border Inside width

With box-sizing: border-box, the browser subtracts padding and border from the stated width to calculate the content area: 300 − 48 − 6 = 246px of actual content space. The rendered box stays exactly 300px — what you declare is what you get.

Step 3 — Padding Fills With Background Color

Padding is transparent to the layout but takes the element’s background-color. This creates the visual breathing room you see between the text and the border. Padding is part of the element’s clickable/interactive area.

Step 4 — Border Wraps Padding and Content

The border ring sits between padding and margin. It can be coloured, dashed, dotted, or invisible (border: none). In border-box mode, its width is subtracted from usable content space rather than added to total width.

Step 5 — Outline for Debugging Does Not Affect Layout

The outline-offset: 8px creates a gap between the element’s border edge and the debug outline ring. This is purely cosmetic — it adds no width to the element, does not move siblings, and does not appear in printed output unless specified.

Real-World Example: Profile Card Layout

<div class="profile-card">
  <div class="avatar">AR</div>
  <div class="profile-info">
    <h2 class="profile-name">Alex Rivera</h2>
    <p class="profile-role">Full-Stack Developer</p>
    <p class="profile-bio">
      Building web apps with React and Node.
      Coffee enthusiast and open-source contributor.
    </p>
    <a href="#" class="profile-btn">View Portfolio</a>
  </div>
</div>
*, *::before, *::after { box-sizing: border-box; }

body {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f1f5f9;
  font-family: system-ui, sans-serif;
  margin: 0;
}

.profile-card {
  width: 360px;
  background: #ffffff;
  border-radius: 16px;
  border: 1px solid #e2e8f0;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.07);
  padding: 32px;          /* inner breathing room */
  margin: 24px;           /* space from page edges */
  text-align: center;
}

.avatar {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  border: 3px solid #6366f1;
  background: #ede9fe;
  color: #4f46e5;
  font-size: 1.4rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 16px;
}

.profile-name {
  font-size: 1.25rem;
  color: #0f172a;
  margin: 0 0 4px;
}

.profile-role {
  font-size: 0.875rem;
  color: #6366f1;
  font-weight: 600;
  margin: 0 0 12px;
}

.profile-bio {
  font-size: 0.9rem;
  color: #64748b;
  line-height: 1.6;
  margin: 0 0 20px;
}

.profile-btn {
  display: inline-block;
  padding: 10px 24px;     /* vertical + horizontal inner spacing */
  background: #6366f1;
  color: white;
  text-decoration: none;
  border-radius: 8px;
  font-size: 0.875rem;
  font-weight: 600;
  border: 2px solid transparent;
  transition: background 0.2s;
}
.profile-btn:hover { background: #4f46e5; }

Common Mistakes

Mistake 1 — Forgetting the global box-sizing reset

❌ Wrong — elements grow beyond their stated width:

/* No reset — default content-box */
.card { width: 300px; padding: 24px; border: 2px solid; }
/* Actual rendered width = 300 + 48 + 4 = 352px */

✅ Correct — always add this at the top of every stylesheet:

*, *::before, *::after { box-sizing: border-box; }
.card { width: 300px; padding: 24px; border: 2px solid; }
/* Actual rendered width = exactly 300px */

Mistake 2 — Using margin for internal spacing

❌ Wrong — margin is outside the border; background color does not fill it:

.btn { margin: 12px 20px; background: #4f46e5; color: white; }
/* Clickable area does not include the margin space */

✅ Correct — use padding for internal spacing inside the element:

.btn { padding: 12px 20px; background: #4f46e5; color: white; }
/* Background and click area both cover the padded region */

Mistake 3 — Leaving debug outlines in production code

❌ Wrong — outline left in shipped CSS causes visual artifacts:

.card { outline: 2px solid red; } /* forgotten debug remnant */

✅ Correct — use a temporary utility class; remove before shipping:

/* Temporary debug helper — remove before deploy */
.debug * { outline: 1px solid rgba(255, 0, 0, 0.3); }

▶ Try It Yourself

Quick Reference

Layer Property Key Notes
Content width, height Use border-box so padding does not expand total size
Padding padding, padding-top etc. Takes background color; part of interactive area
Border border, border-width etc. Shorthand: width style color — all three required
Margin margin, margin-top etc. auto centers block elements horizontally
box-sizing box-sizing: border-box Set globally with *, *::before, *::after
Debug outline outline: 1px solid red No layout impact — safe for debugging

🧠 Test Yourself

An element has box-sizing: border-box, width: 400px, padding: 20px, and border: 5px solid. What is the total rendered width?





▶ Try It Yourself