CSS Positioning — In‑Depth (Easy + Visual)

Quick rule: static (default), relative (nudges itself), absolute (to nearest positioned ancestor), fixed (to viewport), sticky (sticks inside scroll area). Use top/right/bottom/left or shorthand inset to offset. z-index controls overlap when positioned.

1

Static vs Relative

static = default. Offsets are ignored. relative = element keeps its original space, then visually shifts by offsets.

Normal document flow →
A
B (relative
left:30px; top:10px)
C
.relative-demo{ position: relative; left: 30px; top: 10px; }

Notice how B moved visually but its original space is still reserved, so C does not slide under B.

2

Absolute (nearest positioned ancestor)

Absolute elements are taken out of flow and positioned relative to the padding box of the nearest ancestor that is not position: static (or an ancestor that creates a containing block via transform, etc.). If none, they use the initial containing block (page).

I’m absolute → top/right
pin ↙
.container{ position: relative; }
.badge{ position: absolute; top:10px; right:10px; }
.pin{ position: absolute; bottom:10px; left:10px; }
.fill{ position: absolute; inset: 0; }

Always set position: relative on the parent you want to anchor to.

3

Absolute Centering

Classic trick: place top/left at 50% and pull back by half its own size using transform: translate(-50%,-50%).

CENTER
.parent{ position: relative; }
.child{ position: absolute; top:50%; left:50%; transform: translate(-50%, -50%); }
4

Fixed (relative to viewport)

fixed elements are taken out of flow and pinned to the viewport. They don’t move when you scroll. Note: a transformed ancestor can capture a fixed element as its containing block in browsers.

Scroll the page and the red button will stay put.

.fab{ position: fixed; right: 18px; bottom: 18px; }
5

Sticky (hybrid of relative + fixed)

sticky starts as relative. When you scroll past the offset (top/bottom etc.), it behaves like fixed but only inside its nearest scrollable ancestor.

I stick to the top (top: 0)

Content line 1

Content line 2

Content line 3

Content line 4

Content line 5

Content line 6

Content line 7

Content line 8

Content line 9

Content line 10

Content line 11

Content line 12

.scrollbox{ max-height:260px; overflow:auto; }
.sticky-tab{ position: sticky; top: 0; }

Sticky works within the element’s scroll container. If a parent has overflow set (auto/scroll/hidden), that parent becomes the sticky boundary.

6

z-index & Stacking Contexts

z-index controls overlap when elements are in the same stacking context. Positioned elements (non-static) participate; certain properties like opacity < 1 or transform create a new stacking context that isolates children.

z:1
z:2
z:3
New stacking
context
.a{ position:absolute; z-index:1; }
.b{ position:absolute; z-index:2; }
.c{ position:absolute; z-index:3; }
.context .scoped{ transform: translateZ(0); /* new stacking context */ }
7

Offsets: top/right/bottom/left & the inset shorthand

Offsets apply to positioned elements (relative/absolute/fixed/sticky). Use logical shorthands too.

/* physical */
.box{ top: 10px; right: 12px; bottom: 14px; left: 16px; }

/* shorthand */
.box{ inset: 10px 12px 14px 16px; } /* TRBL */
.box{ inset: 0; } /* fill parent */

/* logical (writing‑mode aware) */
.box{ inset-inline-start: 1rem; inset-block-end: 2rem; }

Tip: inset: 0 + position:absolute makes an element fill its positioned parent (great for overlays).

8

Cheat‑Sheet (When to use what?)

9

Gotchas & Pro Tips