Positioning

CSS · Practical · 12 min

Badges, dropdowns, sticky headers and overlays all depend on positioning and on finding the right containing block.

position decides how top, right, bottom, left (or the shorthand inset) are applied.

  • static (default): normal flow; inset properties do nothing.
  • relative: stays in flow, but is shifted visually by the offsets. Its original space is kept. Mostly used as an anchor for absolutely positioned children.
  • absolute: taken out of flow (siblings close the gap) and positioned relative to its containing block: the nearest ancestor whose position isn't static. If none exists, the initial containing block (the viewport-sized area at the top of the page) is used.
  • fixed: positioned relative to the viewport; it stays put when the page scrolls. (An ancestor with a transform or filter becomes its containing block instead, a famous gotcha.)
  • sticky: behaves like relative until scrolling would move it past its offset, e.g. top: 0, then sticks within its parent's bounds.

The common pattern for a badge on a card: parent position: relative, child position: absolute; top: 8px; right: 8px. inset: 0 on an absolute child covers the parent completely, which is ideal for overlays.

When sticky doesn't stick, the cause is almost always an ancestor with overflow: hidden or auto (sticky then sticks inside that scroll box), or a parent no taller than the sticky element itself.

Positioned elements can overlap; z-index orders them, covered in the stacking context lesson.

Example

/* <div class="card"><span class="badge">New</span>...</div> */
.card { position: relative; }      /* containing block for the badge */
.badge {
  position: absolute;
  top: 8px;
  right: 8px;
}

.overlay { position: absolute; inset: 0; background: rgb(0 0 0 / 50%); }

.site-header {
  position: sticky;
  top: 0;                          /* sticks when it reaches the top */
  background: white;
  z-index: 10;
}

.chat-button { position: fixed; right: 1rem; bottom: 1rem; }

Remember

  • absolute is relative to the nearest positioned ancestor
  • relative keeps the original space; absolute removes it
  • sticky needs an offset (top: 0) and breaks inside overflow ancestors
  • inset: 0 fills the containing block

Watch out for

  • A sticky header that never sticks because an ancestor has overflow: hidden.

Check yourself

  1. An absolutely positioned child has top: 0; right: 0, but its parent is position: static. What is it positioned against?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/position