Positioning — Breaking Out of Flow
Flexbox and Grid arrange elements in a predictable flow. But sometimes you need an element that breaks out of that flow — a notification badge floating over an icon, a sticky header that stays visible while the page scrolls, a tooltip that hovers above content. That is where CSS positioning comes in.
Every element has a position property. By default it is static, which means it just lives in normal flow. The moment you change it to anything else, you gain superpowers — and a few new responsibilities.
The four values
Section titled “The four values”position: static — The default. Elements sit in normal document flow. top, left, right, bottom, and z-index have no effect.
position: relative — The element stays in the normal flow, but you can now nudge it with top/left/right/bottom. More importantly, it creates a positioning context — any absolute children will be positioned relative to this element, not the whole page. Think of it as “I want this element to be the origin point for my badge.”
position: absolute — The element is removed from normal flow entirely. It is placed relative to the nearest ancestor that has a non-static position. Other elements in the flow do not see it — they act as if it is not there. Perfect for badges, tooltips, dropdowns, and overlays.
position: sticky — A hybrid. The element sits in normal flow until you scroll past a threshold, then it “sticks” to the viewport edge (defined by top, right, etc.) until its parent scrolls out of view. Perfect for navigation bars and table headers.
The z-index property
Section titled “The z-index property”When positioned elements overlap, z-index controls which one appears on top. Higher numbers are on top. It only works on elements that have a non-static position.
Think of it exactly like the Figma layer order panel — higher in the stack = on top — except in CSS you express it as a number instead of dragging.
Editable example — badge over a card
Section titled “Editable example — badge over a card”Things to try:
- Change
.badgetop: -8pxandright: -8pxto different values — move the badge around - Change
.badgeposition: absolutetoposition: relative— watch it fall back into normal flow - Remove
position: relativefrom.card— the badge will now position relative to the whole document - Change
.sticky-barfromposition: stickytoposition: relative— it stops sticking when you scroll