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:
┌─────────────────────────────────┐
│ 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.
.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.
/* 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:
*, *::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 |
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.
.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:
.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-boxglobally, then being surprised when adding padding to a fixed-width element makes it visually wider than intended. - Using
position: absolutewithout aposition: relative(or similar) ancestor, causing the element to position itself relative to the viewport instead of the intended container. - Confusing
fixedandsticky—fixednever moves with scroll at all;stickymoves normally until a threshold, then "sticks."