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

  • static is the default, normal positioning
  • relative keeps the element’s space and can anchor descendants
  • absolute positions against the containing block and takes no space
  • fixed positions against the viewport and stays put when you scroll
  • sticky flows 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