Skip to content
AgileLogics
7 min read

Positioning

Prerequisites: The box model

position takes an element out of the normal flow (or nudges it within it). The offset properties top, right, bottom, left (or inset for all four) then move it.

Value Positioned relative to Leaves a gap in the flow?
static — (the default; offsets ignored) —
relative Its own normal position Yes
absolute The nearest positioned ancestor No
fixed The viewport No
sticky Normal flow, until it hits an offset while scrolling Yes

Absolute inside relative

The classic pattern: a relative parent becomes the containing block for absolute children.

<style>
  body { margin: 0; }
  .card { position: relative; width: 300px; height: 200px; margin: 50px; }
  .badge { position: absolute; top: 10px; right: 10px; width: 60px; height: 20px; }
  .cover { position: absolute; inset: 0; }
</style>
<div class="card">
  <span class="badge">New</span>
  <a class="cover" href="/product" aria-label="View product"></a>
</div>
<script>
  const r = sel => document.querySelector(sel).getBoundingClientRect();
  console.log("card:", r(".card").left, r(".card").top);
  console.log("badge:", r(".badge").left, r(".badge").top);
  console.log("cover:", r(".cover").width, "x", r(".cover").height);
</script>
card: 50 50
badge: 280 60
cover: 300 x 200
  • The badge sits 10px from the card's top-right corner: 50 + 300 − 10 − 60 = 280px from the left of the page.
  • inset: 0 stretched the link over the entire card — a common way to make a whole card clickable.
  • Without position: relative on the card, both would be positioned against the page instead.

Fixed and sticky

.cookie-banner { position: fixed; inset-inline: 0; bottom: 0; }

.site-header { position: sticky; top: 0; z-index: 10; background: white; }

th { position: sticky; top: 0; }
  • fixed elements stay put while the page scrolls. Make sure they don't cover content — especially on small screens and when zoomed.
  • sticky elements scroll normally until they reach the offset, then stick — within their parent. It needs an offset (top: 0) and fails if an ancestor has overflow: hidden or auto.

Centering an absolute element

.modal {
  position: fixed;
  inset: 0;
  margin: auto;
  width: min(30rem, 90vw);
  height: fit-content;
}

With inset: 0 and margin: auto, the browser centers a box of known size. (The native dialog element does this for you.)

Don't lay out pages with position

Absolute positioning removes elements from the flow, so nothing reacts to their size — text overlaps as soon as content changes. Use Flexbox and Grid for layout, and position for overlays, badges, tooltips, and sticky headers.