The 5 position values — side by side
The stage is position:relative (a positioned ancestor) with overflow:auto —
so it is BOTH the anchor for the absolute box AND the scroll container for the
sticky box. Scroll inside the stage to watch sticky pin,
and scroll the page to watch the fixed chip stay put.
Scroll me ↓ — overflow:auto makes this box a scroll container.
More content to make the stage scrollable. A stickily-positioned element flows normally until it crosses its top threshold, then it sticks to the nearest scrolling ancestor.
An absolutely-positioned box is taken OUT of normal flow — no space is reserved. It anchors to its nearest positioned ancestor (this stage), at the offset given by top/left.
Keep scrolling ↓ — the gold sticky box above should stay pinned at top:6px while the rest of this text moves under it.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
Trailing filler so the absolute box (bottom) and sticky box both have room to demonstrate their behaviour.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.
| value | computed | offsetLeft | offsetParent |
|---|---|---|---|
| static | — | — | — |
| relative | — | — | — |
| absolute | — | — | — |
| sticky | — | — | — |
| fixed | — | — | — |
offsetParent = the nearest positioned ancestor (the containing block for positioned boxes).
For fixed it is null (the containing block is the viewport, not an element).
The stacking context — why z-index "doesn't reach outside"
Two positioned parents overlap. The indigo childA has a huge
z-index:999. By default its z-index competes at the root and it wins. But the moment its
parent (parentA) gets transform:translateZ(0), parentA
becomes a stacking context and traps childA inside it — so the whole parentA unit (z-index auto ≈ 0)
loses to parentB (z-index 1). Toggle it and watch elementFromPoint()
flip which box is on top at the overlap.
document.elementFromPoint(x, y) returns the topmost element at a pixel — the live paint
order. childA(999) on top ⇒ no parent context; parentB(1) on top ⇒ parentA trapped childA.