Flexbox and Grid
Position elements
Use relative, absolute, fixed, sticky, and inset utilities while keeping normal document flow as the default layout tool.
Most layouts should use normal flow, Flexbox, or Grid. Positioning is for the exceptions: a badge in a corner, a sticky header, a fixed toolbar.
Here’s a badge anchored to a card:
<article class="relative">
<span class="absolute end-2 top-2">New</span>
</article>
relative on the article does two things. It keeps the article in normal flow, and it makes it the containing block for any positioned descendant. absolute on the badge pulls it out of flow. end-2 and top-2 set the offsets: end-2 is the logical inline end, so it becomes the right side in English, and top-2 is 0.5rem from the top.
Without relative on the article, the badge would position itself against the nearest positioned ancestor, which might be the whole page.
The five position modes
staticis the default, normal positioningrelativekeeps the element’s space and can anchor descendantsabsolutepositions against the containing block and takes no spacefixedpositions against the viewport and stays put when you scrollstickyflows normally until it hits its inset threshold, then sticks inside its scroll container
Sticky needs an inset
A sticky header does nothing without top-0 or a similar offset. And when it still doesn’t stick, look at the ancestors. An ancestor with overflow: hidden or overflow: auto becomes the scroll container, and the element sticks inside that instead of the page. Not enough content to scroll also makes sticky look broken.
Overlap and meaning
Positioned elements can cover content. If the “New” badge might overlap a heading, add padding to make room, then test with a long title and 200% text zoom. If the badge carries meaning, keep it in the accessibility tree. Purely decorative overlays should be hidden with aria-hidden.
z-index has limits
z-10 only reorders elements within the same stacking context. A transform, an opacity below 1, isolation: isolate, or a positioned ancestor with its own z-index creates a new context. That’s why z-[9999] sometimes still sits behind a sibling’s dropdown. Inspect the stacking contexts in DevTools before piling on bigger numbers.
Try this: add an absolute badge and a sticky section heading to a card list. Zoom the text to 200%, give one card a long title, and wrap the whole list in an overflow-auto container. For each result, write down which containing block and which scroll container is in charge.
Lesson completed