Positioning, stacking and overflow
Static through fixed, the containing block, sticky behaviour, z-index and stacking contexts, scroll containers and aspect ratio.
The five positioning modes
position | Left in normal flow? | Resolves against |
|---|---|---|
static | Yes | Nothing — offsets are ignored |
relative | Yes, space is preserved | Its own original position |
absolute | No, removed from flow | The nearest positioned ancestor, else the initial containing block |
fixed | No | The viewport, unless an ancestor creates a containing block |
sticky | Yes | Its scrollport, once the inset threshold is crossed |
.card { position: relative; } /* becomes the containing block */
.badge {
position: absolute;
inset-block-start: 8px; /* logical top */
inset-inline-end: 8px; /* logical right */
}
.site-header {
position: sticky;
top: 0;
z-index: 10;
}Sticky elements need an inset threshold such as top: 0 to have a position to stick at, and they only travel within their own parent. If the parent is shorter than the scroll distance, the element stops when the parent ends.
position: sticky element silently stops working if any ancestor sets overflow: hidden, auto or scroll. That ancestor becomes the element's scrollport, and it never scrolls — remove the overflow from the ancestor instead of adding more positioning.z-index and stacking contexts
z-index only applies to positioned elements or to flex and grid children. More importantly, it only competes with siblings inside the same stacking context: a large number cannot escape its parent's arena.
.modal { position: fixed; z-index: 100; }
.tooltip { position: absolute; z-index: 200; } /* still behind the modal if trapped */
.card { isolation: isolate; } /* deliberate, explicit stacking context */- A stacking context is created by positioning plus a non-auto
z-index,opacitybelow 1, atransform,filterorbackdrop-filter,will-change,contain: paint,isolation: isolate, and flex or grid children with az-index. - Children of a stacking context are painted as one unit: no descendant can rise above a sibling of its ancestor.
- Within one context, painting order runs background, then negative z-index, then in-flow blocks, then floats, then inline content, then z-index zero and above.
- Replace the z-index arms race with a small named scale, and document it next to the layer declaration.
Overflow, scroll containers and aspect ratio
overflow decides what happens when content is larger than its box. Making a box scroll also makes it a scroll container, which changes how it clips, how it behaves with sticky children, and whether it can scroll-chain into the page behind it.
.scroller {
overflow: auto;
max-block-size: 60vh;
overscroll-behavior: contain; /* do not chain scrolling to the page */
}
.thumb {
inline-size: 100%;
aspect-ratio: 16 / 9;
object-fit: cover; /* crop instead of distort */
}overflowon one axis forces the other away fromvisible, which is a common source of surprise.aspect-ratioreserves height from a width, so media never shifts the layout while loading.object-fit: coverfills the box without distortion;containletterboxes instead.- Give scrollable regions keyboard focus so they can be scrolled without a mouse.
- Prefer
overflow: clipwhen you want clipping without creating a scroll container.
FAQ
Why does my z-index have no effect?
static, or an ancestor created a stacking context and trapped it. Find the ancestor with a transform, filter or opacity value and reconsider which one needs its own context.What is the difference between absolute and fixed?
Related
Modern selectors and cascade control Debugging CSS, resets and browser support
Last refreshed 2026-09-18.