In CSS, on which elements does the z-index property actually have an effect?
answer
- parses fine, does nothing
- check the computed position first
- flex and grid items are the exception
- auto and 0 paint alike, differ below
basics
~20 sz-index applies to positioned elements — those with position relative, absolute, fixed, or sticky — and also to flex items and grid items, which honour z-index even while position stays static. On any other element the declaration is ignored.
solid answer
~40 sz-index only takes effect on an element that participates in stacking as its own unit. That means positioned elements — `position: relative`, `absolute`, `fixed`, or `sticky` — and, as a special case added by the Flexbox and Grid specs, direct children of a flex or grid container, which honour `z-index` even with `position: static`. Everywhere else the declaration parses fine and does nothing, which is why `z-index: 10` on a plain block seems silently ignored. One more detail worth saying: on a positioned element, `z-index: auto` and `z-index: 0` paint at the same level, but `0` creates a stacking context and `auto` does not — so switching `auto` to `0` can change how *descendants* stack even though the element itself does not move.
code
css · 20 lines.ignored {
/* position defaults to static -> z-index has no effect */
z-index: 999;
}
.works {
position: relative;
z-index: 2;
}
.stack { display: grid; }
.stack > .front {
/* grid item: honoured with position still static */
grid-area: 1 / 1;
z-index: 2;
}
.stack > .back {
grid-area: 1 / 1;
z-index: 1;
}go deeper
Memorise the applicability rule: positioned elements plus flex and grid items. When z-index looks ignored, check the computed position before touching the number.
Explain why a static box has no stack level to assign, and articulate the auto-versus-0 difference: same paint level, but only 0 seals descendants into a new context.
Point out the downstream consequence — flipping auto to 0 on a wrapper silently confines every positioned descendant, which is a frequent regression when someone normalises values across a stylesheet.
Decide the convention: whether components may set z-index at all, whether wrappers declare an explicit containment value, and how that keeps overlay behaviour predictable as the codebase grows.
## The property and its applicability `z-index` takes an integer (positive, zero, or negative) or the keyword `auto`. Its initial value is `auto`, and it is **not inherited**. The important part for interviews is which elements it *applies to*, because on everything else it is parsed, stored, and then ignored. It applies to: - **Positioned elements** — anything whose computed `position` is `relative`, `absolute`, `fixed`, or `sticky`. This is the classic rule. - **Flex items** — direct children of a `display: flex` or `display: inline-flex` container. - **Grid items** — direct children of a `display: grid` or `display: inline-grid` container. The flex and grid cases are exceptions carved out by their own specifications: a flex or grid item with a `z-index` other than `auto` creates a stacking context and is painted at that level *even though its `position` is still `static`*. Interviewers like this one because it contradicts the rule people memorised. ```css .stack { display: grid; } .stack > .a { grid-area: 1 / 1; z-index: 2; } /* wins — no position needed */ .stack > .b { grid-area: 1 / 1; z-index: 1; } ``` That snippet is the common single-cell overlap pattern: two grid items placed in the same cell, ordered purely by `z-index`, with `position` left alone. ## Why static elements ignore it An unpositioned, non-flex, non-grid box is painted as part of its parent's in-flow content, in the ordinary block/inline painting order. It has no independent stack level to assign, so there is nothing for the integer to mean. The browser does not warn you; the rule simply does not apply, which is why `z-index: 999` on a plain `<div>` looks like a bug in the browser rather than a no-op in your CSS. The first debugging move when `z-index` seems ignored is therefore to check the computed `position` — not to raise the number. ## auto versus 0 This distinction is small, real, and frequently asked. - `z-index: auto` — the element is painted at the same level as a stack level of 0, but it does **not** create a stacking context. Its positioned descendants keep participating in the *outer* context. - `z-index: 0` — the element is painted at the same level, but it **does** create a stacking context. Its descendants are now sealed inside it. Visually, flipping `auto` to `0` on the element itself changes nothing. What changes is everything below it: a descendant that used to be able to out-stack elements elsewhere on the page is now confined. This is a common accidental cause of "my dropdown stopped escaping its card". ## Negative values `z-index` accepts negatives, and they are useful: a decorative pseudo-element with `z-index: -1` slides behind its parent's text while remaining in front of the parent's own background and borders. The trap is that it only stays behind the *content* — if the parent does not create a stacking context, the negative child can slip behind an ancestor's background and vanish. Giving the parent `position: relative; z-index: 0` (or `isolation: isolate`) contains it. ## What to say in an interview "z-index applies to positioned elements, plus flex and grid items as a spec-level exception. On anything else it is a no-op, so when it appears ignored I check the computed position first. And `auto` versus `0` matters — same paint level, but only `0` creates a stacking context." That covers the rule, the exception, the debugging reflex, and the nuance in four sentences.
- Why do flex and grid items honour z-index without being positioned?Their own specifications say so. Flex and grid items are painted like inline-blocks, and both specs add that a `z-index` other than `auto` creates a stacking context and orders the item even when `position: static`. It exists so overlapping items placed in the same grid cell or flex line can be ordered without forcing positioning on them.
- An element has z-index: -1 and disappears entirely. What happened?It painted behind an ancestor's background. A negative child sits behind its stacking-context parent's in-flow content but in front of that parent's own background — so if the parent never created a stacking context, the child sinks past it to whatever opaque ancestor is below. Give the parent `isolation: isolate` or `position: relative; z-index: 0` to contain it.
saying these in an interview costs you the question
- Claims z-index works on any element regardless of position
- Does not know flex and grid items are an exception
- Treats z-index: auto and z-index: 0 as fully identical
- Thinks z-index is inherited from the parent
- Believes negative z-index values are invalid