Positioning lets you take elements out of the normal flow and place them precisely — badges on cards, sticky headers, modals, tooltips. It is powerful but trips up beginners, so let us make it clear.
The five position values
| Value | Behaviour |
|---|---|
| static | Default — normal flow, ignores top/left |
| relative | Normal flow, but can be nudged with offsets |
| absolute | Removed from flow, positioned to nearest positioned ancestor |
| fixed | Removed from flow, positioned to the viewport |
| sticky | Normal until scrolled to a threshold, then sticks |
Relative + absolute: the key combo
The most common pattern: set a parent to <code>position: relative</code>, then a child to <code>position: absolute</code>. The child is now positioned relative to that parent — perfect for badges, overlays and tooltips.
<div class="card"><span class="badge">New</span>Product card</div>.card{position:relative;background:#e0f2fe;padding:28px;border-radius:12px}
.badge{position:absolute;top:10px;right:10px;background:#ef4444;color:#fff;padding:3px 9px;border-radius:999px;font-size:.75rem}Sticky positioning
<code>position: sticky</code> is a hybrid: an element behaves normally until you scroll to a threshold (like <code>top: 0</code>), then it sticks in place. It is the modern way to make sticky headers and section labels — no JavaScript needed.
.header {
position: sticky;
top: 0;
}Z-index and stacking contexts
When positioned elements overlap, <code>z-index</code> decides what is on top — higher wins. But there is a catch: z-index only compares elements within the same stacking context. A parent with its own z-index (or opacity, transform, etc.) creates a new context, trapping its children's z-index inside it. This is the source of most "my z-index does nothing" bugs.
.modal { z-index: 99999; }/* ensure the modal is not trapped
inside a low-z-index parent context */
.modal { position: fixed; z-index: 100; }Setting a huge z-index like 9999 to force something on top, when the real problem is a parent stacking context. Fix the context, do not escalate numbers.
Use position: sticky for headers, relative+absolute for overlays, and keep z-index values small and organised (e.g. 10, 20, 100). If z-index seems broken, look for a parent that created a stacking context.
Build a card with position: relative and add an absolutely-positioned "Sale" badge in the top-right corner. Then make a header position: sticky; top: 0 and scroll a tall page to see it stick.
1. absolute positions relative to…
2. Which value sticks after scrolling to a threshold?
3. z-index only compares elements…
4. fixed positions relative to…
- Five positions: static, relative, absolute, fixed, sticky.
- relative parent + absolute child positions overlays and badges.
- position: sticky makes headers stick with no JavaScript.
- z-index only works within a stacking context — fix the context, not the number.