Kodokon kodokon.com

Positioning: relative, absolute, fixed, sticky, z-index

Anchor badges, headers, and modals exactly where you want them with CSS positions and a well-managed z-index scale.

8 min · 3 questions

Open this lesson in Kodokon

By default, every element is position: static and follows the document flow. position: relative has two uses: nudging an element slightly without disturbing its neighbors, and above all serving as the reference for children with position: absolute. It's the most common positioning pattern: a promo badge, a tooltip, or an icon anchored to a corner of its parent.

CSS
.product-card {
  position: relative;
}

.promo-badge {
  position: absolute;
  top: 12px;
  right: 12px;
}
The badge anchors to the card's corner, not the page's.

position: fixed pins an element to the viewport, regardless of scrolling: cookie banner, back-to-top button. position: sticky is a hybrid: the element scrolls normally with the page, then locks in place once it reaches the threshold you define (for example top: 0). It's the modern solution for headers that stay visible.

CSS
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: white;
}
Without the top: 0 threshold, sticky has no effect.

When elements overlap, z-index decides which one sits on top - but only for positioned elements. Adopt a documented scale rather than random values: 10 for dropdown menus, 100 for the header, 1000 for modals. Beware: a parent that creates its own stacking context (for example with an opacity below 1) caps the z-index of all its children.

CSS
.dropdown {
  z-index: 10;
}

.site-header {
  z-index: 100;
}

.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
}
A clear scale avoids the z-index arms race.

Knowledge check

Make sure you remember the key points of this lesson.

  1. Relative to what does a position: absolute element position itself?
    • Always relative to the browser window
    • Relative to the nearest positioned ancestor, otherwise the viewport
    • Relative to its direct parent, whatever its position
  2. This header has to scroll normally, then freeze at the top of the window as soon as it reaches it. Which property is missing to trigger that behavior?
    .site-header {
      position: sticky;
      ___: 0;
      z-index: 100;
      background: white;
    }
    • top
    • bottom
    • margin-top
    • padding-top
  3. Why can a z-index: 999 have no effect?
    • Because the maximum allowed value is 100
    • Because the element isn't positioned, or is trapped in a lower stacking context
    • Because z-index only works with Grid