The position property changes how an element participates in layout and how its offset properties (top/right/bottom/left) behave.
| Value | Behavior |
|---|---|
static (default) | Normal document flow; top/left/z-index have no effect |
relative | Stays in normal flow, but can be nudged with top/left/etc., relative to where it would have been |
absolute | Removed from normal flow entirely, positioned relative to the nearest ancestor with a non-static position (or the initial containing block, if none exists) |
fixed | Positioned relative to the viewport; stays put when the page scrolls |
sticky | Behaves like relative until a scroll threshold is crossed, then "sticks" like fixed within its containing block |
The most common absolute pattern is pairing it with a relative parent used purely as a positioning anchor:
.card {
position: relative; /* becomes the reference point for .badge below */
}
.badge {
position: absolute;
top: 8px;
right: 8px;
}
z-index only has an effect on elements whose position is something other than static — a common source of "I set z-index: 999 and nothing happened" bugs is simply forgetting to also set position: relative (or another non-static value) on the element.
z-index values don't compete globally — they only compete within the same stacking context. Several CSS properties create a brand-new stacking context for an element and everything inside it, which isolates its z-index values from the rest of the page:
z-index other than autoopacity less than 1transform, filter, or will-change set to a value other than none.parent-a { position: relative; z-index: 1; }
.child-a { position: relative; z-index: 9999; } /* still can't escape .parent-a's stacking context */
.parent-b { position: relative; z-index: 2; } /* .parent-b sits above .parent-a as a whole */
.child-a's z-index: 9999 only wins within .parent-a — it can never appear above .parent-b's content as long as .parent-b's own stacking context (z-index: 2) is above .parent-a's (z-index: 1). This is the real explanation behind "I set an insanely high z-index and it still renders behind something" — the element is trapped inside a lower stacking context created by one of its ancestors.