CodeMIRAI
0 XP

Positioning

3 min read 6 runnable examples Quiz included

position takes an element partly or fully out of the normal flow, and lets you place it with top, right, bottom and left. The default, static, means "in the normal flow", where those four properties do nothing.

staticnormal flowrelativemoved, space keptabsoluteplaced in its parentfixedpinned to the screentop: 12px; left: 18pxposition: relativextop
relative moves a box but keeps its old space; absolute takes it out of the flow, placed against the nearest positioned ancestor; fixed stays put while the page scrolls.

relative: nudged from where it would be

HTML
<style>
  body { font-family: system-ui; }
  .box { display: inline-block; width: 90px; padding: 14px 0; text-align: center; background: #eef0ff; border: 2px solid #5a48f5; }
  .moved { position: relative; top: 20px; left: 20px; background: #fff4dc; }
</style>
<div class="box">1</div>
<div class="box moved">2, moved</div>
<div class="box">3</div>

Box 2 shifts, but its original space stays reserved, so box 3 doesn't move. On its own, relative is rarely needed; its main job comes next.

absolute: placed inside a positioned parent

An absolutely positioned element leaves the flow completely, and is placed relative to its nearest positioned ancestor, meaning one whose position isn't static:

HTML
<style>
  body { font-family: system-ui; padding: 12px; }
  .card { position: relative; width: 220px; padding: 16px; border-radius: 12px; background: #f4f2ff; border: 1px solid #d8d3ff; }
  .badge { position: absolute; top: -10px; right: -10px; padding: 4px 10px; border-radius: 999px;
           background: #e0446a; color: white; font-size: 12px; font-weight: 700; }
</style>
<div class="card">
  <span class="badge">NEW</span>
  <strong>React course</strong>
  <p>Components, state and hooks.</p>
</div>

position: relative on the card makes it the reference point, so the badge lands on the card's corner. Remove it, and the badge flies off to the corner of the page.

Overlays and exact centring

HTML
<style>
  body { font-family: system-ui; }
  .photo { position: relative; width: 320px; }
  .photo img { display: block; width: 100%; border-radius: 10px; }
  .caption { position: absolute; inset: auto 0 0 0; padding: 10px 14px; color: white; border-radius: 0 0 10px 10px;
             background: linear-gradient(transparent, rgba(0, 0, 0, .75)); }
  .play { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
          width: 54px; height: 54px; border-radius: 50%; background: rgba(255, 255, 255, .9);
          display: grid; place-items: center; font-size: 22px; }
</style>
<div class="photo">
  <img src="https://picsum.photos/seed/coast/640/400" alt="A coastline">
  <div class="play">▶</div>
  <div class="caption">Coastline at sunset</div>
</div>
  • inset: auto 0 0 0 is shorthand for top: auto; right: 0; bottom: 0; left: 0: a bar stretched along the bottom edge.
  • top: 50%; left: 50% puts the button's top-left corner in the middle; transform: translate(-50%, -50%) then pulls it back by half its own size, centring it exactly.

fixed: stays put while the page scrolls

Scroll inside this preview:

HTML
<style>
  body { font-family: system-ui; }
  .tall { height: 800px; padding: 12px; background: linear-gradient(#eef0ff, #d9f7ea); }
  .chat { position: fixed; right: 16px; bottom: 16px; padding: 10px 16px; border-radius: 999px;
          background: #5a48f5; color: white; box-shadow: 0 6px 16px rgba(0, 0, 0, .2); }
</style>
<div class="tall">Scroll down. The chat button stays in the corner.</div>
<div class="chat">💬 Chat</div>

A fixed element is placed relative to the viewport (here, the preview box) and ignores scrolling: think chat buttons, cookie banners and "back to top" links.

sticky: scrolls until it reaches an edge

HTML
<style>
  body { font-family: system-ui; margin: 0; }
  .list { height: 220px; overflow-y: auto; border: 1px solid #ddd; }
  h3 { position: sticky; top: 0; margin: 0; padding: 8px 12px; background: #5a48f5; color: white; }
  p { margin: 0; padding: 8px 12px; border-bottom: 1px solid #eee; }
</style>
<div class="list">
  <h3>A</h3><p>Asha</p><p>Alan</p><p>Ada</p><p>Amir</p>
  <h3>B</h3><p>Bea</p><p>Bruno</p><p>Bilal</p><p>Bo</p>
  <h3>C</h3><p>Carlos</p><p>Chen</p><p>Chloe</p><p>Cyrus</p>
</div>

Scroll the list: each letter sticks to the top until the next one pushes it away. A sticky element scrolls normally until it reaches its top value, then holds there, but never leaves its parent. Sticky table headers and section titles work this way.

z-index: what's on top

HTML
<style>
  body { font-family: system-ui; }
  .stack { position: relative; height: 150px; }
  .stack div { position: absolute; width: 110px; height: 80px; padding: 8px; box-sizing: border-box;
               border-radius: 10px; color: white; }
  .a { background: #5a48f5; top: 0;    left: 0;     z-index: 3; }
  .b { background: #0aa9cf; top: 25px; left: 60px;  z-index: 2; }
  .c { background: #e0663a; top: 50px; left: 120px; z-index: 1; }
</style>
<div class="stack">
  <div class="a">z-index 3</div>
  <div class="b">z-index 2</div>
  <div class="c">z-index 1</div>
</div>

A higher z-index is drawn on top. It works on positioned elements, and on flex and grid items. Without it, elements later in the HTML are drawn over earlier ones.

Finished this lesson?Mark it complete to earn +20 XP and move your progress on.