How does z-index work in CSS?
z-index controls stacking order, but only works on positioned elements inside the same stacking context.
CSSLayout
Overview
z-index sets which element appears in front when elements overlap. Higher values are in front. It sounds simple, but stacking contexts make it surprising: a z-index of 9999 inside a context with a low z-index will still sit behind elements outside that context.
Key Points
- •z-index only works on elements with `position` set to anything other than `static`.
- •A new stacking context is created by: `position` + `z-index`, `opacity < 1`, `transform`, `filter`, `isolation: isolate`, and several others.
- •Elements within a stacking context are painted together their z-indices are compared only within that context.
- •`z-index: auto` (default) does not create a new stacking context.
- •Use `isolation: isolate` on a container to prevent internal z-index from bleeding out.
Examples
Basic z-index stacking
css.behind { position: relative; z-index: 1; }
.infront { position: relative; z-index: 2; } /* renders on top */The stacking context trap
css/* Parent creates a stacking context at z-index: 1 */
.modal-backdrop {
position: fixed;
z-index: 1;
opacity: 0.5; /* <-- this alone creates a stacking context */
}
/* Even z-index: 9999 inside .modal-backdrop can't escape z-index: 1 */
.modal-backdrop .close-btn {
position: relative;
z-index: 9999; /* only beats other elements INSIDE .modal-backdrop */
}opacity < 1 always creates a stacking context a common source of confusion.
Use isolation: isolate to contain a component
css.dropdown-component {
isolation: isolate; /* internal z-index stays inside this component */
}Pro Tip
When z-index isn't working, open DevTools and check whether a parent element has `opacity`, `transform`, or `filter` these create a stacking context and contain z-index. Adding `isolation: isolate` to the container is usually the cleanest fix.