Box Model & Layout

Content, padding, border and margin, box-sizing: border-box, display types, and the position property.

The box model

Every element on a page is rendered as a rectangular box made of four layers, from the inside out:

Plaintext
┌─────────────────────────────────┐
│            margin                │
│  ┌─────────────────────────────┐ │
│  │          border              │ │
│  │  ┌───────────────────────┐  │ │
│  │  │       padding          │  │ │
│  │  │  ┌─────────────────┐  │  │ │
│  │  │  │     content      │  │  │ │
│  │  │  └─────────────────┘  │  │ │
│  │  └───────────────────────┘  │ │
│  └─────────────────────────────┘ │
└─────────────────────────────────┘
  • Content — the actual text, image, or nested elements.
  • Padding — space between the content and the border; part of the element's clickable/visible background.
  • Border — a visible (or invisible) line around the padding.
  • Margin — space outside the border, separating this element from its neighbors. Margin is always transparent and never shows a background color.
Css
.box {
    width: 300px;
    padding: 20px;
    border: 2px solid #3b82f6;
    margin: 16px;
}

box-sizing: border-box

By default (box-sizing: content-box), width/height only set the content box — padding and border are added on top, so a 300px-wide box with 20px padding and a 2px border actually renders at 344px wide. This trips up almost everyone at some point.

Css
/* content-box (default) — width is content-only */
.content-box {
    box-sizing: content-box;
    width: 300px;
    padding: 20px;
    border: 2px solid black;
    /* rendered width: 300 + 20*2 + 2*2 = 344px */
}

/* border-box — width includes padding and border */
.border-box {
    box-sizing: border-box;
    width: 300px;
    padding: 20px;
    border: 2px solid black;
    /* rendered width: 300px, exactly */
}

border-box is almost universally preferred because it makes sizing predictable — width: 300px always means 300px on screen, regardless of padding or border. It's so standard that most CSS resets apply it globally:

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

display: block, inline, and inline-block

The display property controls how an element participates in layout.

Value Starts new line? Respects width/height? Respects vertical margin/padding?
block Yes Yes Yes
inline No No No (horizontal only)
inline-block No Yes Yes
Css
span { display: inline; }        /* default for <span> */
div  { display: block; }         /* default for <div> */

.badge {
    display: inline-block;       /* flows inline, but accepts width/height */
    width: 24px;
    height: 24px;
    padding: 4px;
}

inline-block is the classic way to get block-like sizing while still flowing in line with text — useful for things like tag/badge components sitting inline with a sentence.

Positioning

The position property takes an element out of (or changes) its normal document flow.

Css
.relative {
    position: relative;
    top: 10px;   /* nudges 10px down from where it would normally sit */
    left: 5px;
}

.absolute {
    position: absolute;
    top: 0;
    right: 0;    /* positioned relative to the nearest positioned ancestor */
}

.fixed {
    position: fixed;
    bottom: 20px;
    right: 20px; /* stays in place even as the page scrolls */
}

.sticky {
    position: sticky;
    top: 0;      /* behaves like relative, until it hits the scroll boundary, then sticks like fixed */
}
Value Behavior
static Default. Normal document flow; top/left/etc. have no effect.
relative Stays in normal flow, but top/left/right/bottom offset it from where it would otherwise be. Also establishes a positioning context for any absolute descendants.
absolute Removed from normal flow entirely; positioned relative to the nearest ancestor with a position other than static (or the viewport, if none exists).
fixed Removed from flow; positioned relative to the browser viewport, ignoring scrolling.
sticky A hybrid — acts relative until a scroll threshold is crossed, then acts fixed within its containing block.

A very common pattern: a relative parent containing an absolute child, used to position a badge or close button precisely inside a card:

Css
.card {
    position: relative;
}

.card .close-button {
    position: absolute;
    top: 8px;
    right: 8px;
}

Common mistakes

  • Forgetting that margins on adjacent block elements can collapse into a single margin (the larger of the two) instead of adding together — a frequent source of "why is there less space than I set" confusion.
  • Not applying box-sizing: border-box globally, then being surprised when adding padding to a fixed-width element makes it visually wider than intended.
  • Using position: absolute without a position: relative (or similar) ancestor, causing the element to position itself relative to the viewport instead of the intended container.
  • Confusing fixed and stickyfixed never moves with scroll at all; sticky moves normally until a threshold, then "sticks."