CSS Position

Move elements with relative, absolute, fixed and sticky, and stack them with z-index.

Lesson 17 of 49Intermediate13 min read

Normally, elements sit in the flow of the page, one after another from top to bottom. The position property lets you step outside that flow. You can pin a badge to the corner of a card, keep a header at the top of the screen while the page scrolls, or float a chat button in the bottom-right corner.

Positioning is powerful but easy to overuse. It's meant for small, specific placements. For general page layout, such as columns and rows, Flexbox and Grid are far more reliable, because positioned elements don't make room for each other.

The five position values

ValueMoves relative toStays in the flow?
staticNothing; this is the default and offsets have no effectYes
relativeIts own normal positionYes, and its original space is kept
absoluteThe nearest positioned ancestorNo
fixedThe browser windowNo
stickyActs normally until you scroll to a set point, then sticksYes

Once an element is positioned, use top, right, bottom and left to move it. The shorthand inset: 0 sets all four to 0, which makes an absolute element fill its anchor completely.

The golden rule: absolute inside relative

An absolutely positioned element looks up through its ancestors for the first one whose position isn't static. If it doesn't find one, it positions itself relative to the whole page, which is rarely what you want.

So the classic pattern is:

CSS
.card { position: relative; }          /* the anchor */
.card .badge { position: absolute; top: 8px; right: 8px; }

Setting position: relative on the card without any offsets doesn't move it at all. It simply turns the card into the anchor for the badge.

z-index: which element is on top

When positioned elements overlap, z-index decides the stacking order. A higher number sits closer to the viewer. It only works on positioned elements and on flex or grid children. Keep values simple, such as 1, 10 and 100, so you can still slot something in between later.

If a high z-index seems to have no effect, check the parent. An element can never rise above the stacking level of a parent that creates its own stacking context, for example through opacity or transform.

CSS Position Syntax

Position properties

.parent { position: relative; }
.child  { position: absolute; top: 0; right: 0; z-index: 2; }
.header { position: sticky; top: 0; }
.chat   { position: fixed; bottom: 20px; right: 20px; }

CSS Position Summary

  • position takes elements out of the normal flow for precise placement.
  • relative nudges an element and also acts as an anchor for absolute children.
  • absolute positions an element inside its nearest positioned ancestor.
  • fixed stays put in the window; sticky sticks once you scroll to it.
  • z-index controls which overlapping element appears on top.

CSS Position Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

A badge on a card

.card {
  position: relative;
  width: 240px;
  font-family: sans-serif;
}

.card img { display: block; border-radius: 12px; }

.badge {
  position: absolute;
  top: 10px;
  right: 10px;
  padding: 4px 10px;
  border-radius: 999px;
  background: #e5484d;
  color: white;
  font-weight: bold;
}
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 2The card becomes the anchor for anything absolutely positioned inside it.
  2. Line 10The badge leaves the normal flow…
  3. Lines 11 to 12…and sits 10px from the card's top-right corner.
Example 2

Sticky header and fixed button

Scroll inside the result. The header sticks; the chat button never moves.

.top {
  position: sticky;
  top: 0;
  padding: 10px;
  background: #15161b;
  color: white;
  z-index: 10;
}

.chat {
  position: fixed;
  right: 16px;
  bottom: 16px;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: 0;
  background: #17a865;
  font-size: 22px;
}
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Lines 2 to 3Behaves normally until it reaches the top of the scroll area, then stays there.
  2. Line 7Keeps the header above the content as it scrolls past.
  3. Lines 11 to 13Pinned to the window's bottom-right corner.
Example 3

relative nudge and z-index

.tile {
  position: relative;
  width: 110px;
  padding: 24px 10px;
  border: 2px solid #15161b;
  font: bold 14px sans-serif;
}

.a { background: #ffe3d7; z-index: 1; }
.b { background: #e1e6ff; top: -30px; left: 40px; z-index: 3; }
.c { background: #fff1c2; top: -60px; left: 80px; z-index: 2; }
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 2relative lets us nudge each tile with top/left and use z-index.
  2. Lines 10 to 11B and C are pulled up to overlap A. B's z-index (3) puts it on top of everything.

Common CSS Position Mistakes

Absolute without a positioned parent

Don't
.card .badge { position: absolute; top: 0; right: 0; }
/* the badge flies to the corner of the whole page */
Do
.card { position: relative; }
.card .badge { position: absolute; top: 0; right: 0; }

Sticky without a threshold

Don't
.header { position: sticky; }
Do
.header { position: sticky; top: 0; }

Sticky needs top (or another side) to know when to stick. It also won't work if an ancestor has overflow: hidden.

CSS Position in Real Projects

Position in real UIs

Notification dots on app icons, "SALE" ribbons, close buttons on modals, dropdown menus, tooltips, sticky table headers, cookie banners and floating "back to top" buttons are all built with position. The sticky header on this site uses position: sticky; top: 0.

CSS Position Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Pin the button to the bottom-right of the screen.

.help {
  position: ;
  : 20px;
  right: 20px;
}
Multiple choicemedium

An absolute element is positioned relative to…

Multiple choicemedium

Which element has a z-index that actually works?

Fix the bugmedium

The "NEW" ribbon should sit in the top-left corner of the product box, not the page. Fix it.

.product {
  width: 200px;
  margin: 40px;
  padding: 30px 16px 16px;
  border: 2px solid #15161b;
}

.ribbon {
  position: absolute;
  top: 0;
  left: 0;
  background: #ffd23f;
  padding: 2px 8px;
}
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • The ribbon sits inside the product box
  • Still absolutely positioned

CSS Position Quiz

3 questions to check what you learned.

  1. Which position value is the default?

    • relative
    • absolute
    • static
    • normal
  2. What does position: relative; top: 20px; do?

    • Moves the element 20px up
    • Moves it to 20px from the top of the page
    • Moves the element 20px down from its normal spot, keeping its original space
    • Nothing
  3. Why might position: sticky not work?

    • It's not supported anywhere
    • An ancestor has overflow: hidden, or no top value is set
    • It needs z-index
    • It only works on headers

CSS Position Challenge

Avatar with an online dot

Make a green "online" dot sit on the bottom-right of the avatar:

  1. .avatar should be the positioned parent
  2. .dot is position: absolute with right and bottom of 4px
  3. .dot is a 14px green circle
.avatar { width: 80px; }
.avatar img { display: block; border-radius: 50%; }
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Avatar is the positioned parent
  • Dot is absolute
  • Dot sits near the bottom-right of the avatar
  • Dot is a 14px circle
  • Dot is green