Z index in CSS controls stacking order. It decides which element appears in front when elements overlap. This is important for dropdown menus, modals, tooltips, sticky headers, overlays, badges, cards, and positioned UI elements. Without understanding z-index, it is easy to create a dropdown that appears behind a header or a modal overlay that does not cover the page correctly.
The z-index property looks simple because it accepts numbers, but the real behavior depends on stacking contexts. A high z-index does not always beat a lower one if the elements are inside different stacking contexts. This is why z-index bugs can feel confusing even when the values look obvious.
Basic Z Index Syntax
The z-index property is commonly used on positioned elements. An element is positioned when its position is relative, absolute, fixed, or sticky.
.dropdown {
position: absolute;
z-index: 1000;
}
This dropdown is positioned and has a z-index of 1000. If it overlaps nearby elements in the same stacking context, it should appear above elements with lower stacking order.
Z Axis and Stacking Order
Normal page layout works mostly on the x-axis and y-axis: left-right and top-bottom. Z-index works on the z-axis: front-back. Higher stacking order appears closer to the user.
If two elements do not overlap, z-index may appear to do nothing. It only matters when elements occupy the same visual area or when one could paint above another.
Default Painting Order
Before using z-index, understand the default painting order. Browser painting is not random. Backgrounds and borders paint first, then normal block content, then positioned content in later layers. If elements do not have explicit z-index values, their order can still be controlled by normal layout and source order.
| Layer | Typical Example |
|---|---|
| Background and border | Section background |
| Normal flow content | Paragraphs and images |
| Positioned descendants | Absolute badge or tooltip |
| Later source order | Later overlapping sibling |
This is why adding z-index to every element is not a good habit. Many elements already paint correctly without it. Use z-index when an element must intentionally sit above or below another overlapping element.
Positioned Elements and Z Index
Historically, z-index mainly applied to positioned elements. In modern CSS, stacking behavior can also involve flex items, grid items, opacity, transform, and other properties. Still, the most common beginner rule is this: if z-index seems not to work, check whether the element is positioned.
.box {
position: relative;
z-index: 10;
}
Adding position: relative without offsets keeps the element in normal flow but allows z-index to apply in a predictable way.
Positive Z Index
Positive z-index values move elements forward within their stacking context. There is no universal meaning for a specific number. A value of 10 is not automatically better than 9999. It only matters compared with nearby stacking values in the same context.
.header {
position: sticky;
top: 0;
z-index: 100;
}
.dropdown {
position: absolute;
z-index: 200;
}
This suggests that the dropdown should appear above the header if both are in compatible stacking contexts. In real projects, stacking context rules still need to be checked.
Negative Z Index
Z-index can use negative values. A negative value can place an element behind other content in the same stacking context. This is sometimes used for decorative backgrounds.
.shape {
position: absolute;
z-index: -1;
}
Negative z-index can be tricky because the element may go behind the parent background or become hard to click or see. Use it carefully and test the result.
Stacking Context
A stacking context is a self-contained stacking group. Elements inside a stacking context are ordered relative to each other, and the whole group is then stacked relative to other groups. This is the part that makes z-index confusing.
If a child has z-index: 9999 inside a stacking context, it may still appear behind another element outside that context. It cannot escape the stacking order of its parent context.
Stacking Context Example
Consider a card with transform applied for animation. That card can create its own stacking context. A tooltip inside the card may have a very high z-index, but it is still trapped inside the card stacking context when compared with elements outside the card.
.card {
transform: translateY(0);
}
.card .tooltip {
position: absolute;
z-index: 9999;
}
If another sibling outside the card belongs to a higher stacking context, the tooltip can still appear underneath it. The fix is not always a bigger number. Sometimes the fix is moving the tooltip in the DOM, removing the stacking-context trigger, or creating a better layer structure.
What Creates a Stacking Context
Several CSS properties can create stacking contexts. Common examples include positioned elements with z-index, fixed and sticky positioning, opacity less than 1, transform, filter, perspective, isolation, mix-blend-mode, and some containment properties.
| Property or Condition | Example |
|---|---|
| position with z-index | position: relative; z-index: 1 |
| opacity less than 1 | opacity: 0.9 |
| transform | transform: translateY(0) |
| filter | filter: blur(0) |
| isolation | isolation: isolate |
| fixed or sticky position | position: fixed |
This means a harmless-looking transform can affect stacking. Many developers add transform for animation or performance and accidentally create a new stacking context.
Using isolation: isolate
The isolation: isolate property intentionally creates a new stacking context. This can be useful when a component should manage its own internal layers without blending into unrelated page layers.
.pricing-card {
position: relative;
isolation: isolate;
}
For example, decorative shapes inside a card can sit behind the card content without accidentally falling behind the entire page. This gives the component a controlled local stacking environment.
Z Index Scale
Large projects often use a z-index scale instead of random values. This keeps layering predictable. For example, base content may use low values, dropdowns higher values, sticky headers higher still, and modals near the top.
:root {
--z-dropdown: 1000;
--z-sticky: 1100;
--z-modal: 2000;
--z-toast: 3000;
}
.modal {
z-index: var(--z-modal);
}
This is easier to maintain than scattering values like 9, 99, 999, and 999999 across the stylesheet. The names describe the layer purpose.
Keep the Scale Small
A good z-index scale does not need hundreds of values. Most websites need only a few layers: base content, raised content, dropdowns, sticky headers, modals, and notifications. If every component invents its own large number, the project becomes harder to debug.
Z Index and Modals
Modals usually need a high stacking layer because they must appear above the main page. A modal often has a backdrop and a dialog box. The dialog should appear above the backdrop.
.modal-backdrop {
position: fixed;
inset: 0;
z-index: 2000;
}
.modal-dialog {
position: fixed;
z-index: 2010;
}
The backdrop covers the page, and the dialog appears above the backdrop. Both use fixed positioning because they relate to the viewport.
Z Index and Dropdowns
Dropdown menus often need z-index so they appear above nearby content. But if an ancestor creates a stacking context or has overflow clipping, z-index alone may not solve the problem.
.menu-item {
position: relative;
}
.dropdown {
position: absolute;
z-index: 1000;
}
If the dropdown is still hidden, inspect parent elements for overflow: hidden, transform, opacity, or z-index. The issue may be clipping or stacking context, not the dropdown value itself.
Z Index vs Overflow Clipping
Z-index controls paint order, but it does not cancel clipping. If a parent has overflow: hidden, a child dropdown can be cut off even with a very high z-index. This is a different problem from stacking order.
.card {
overflow: hidden;
}
.card .menu {
position: absolute;
z-index: 9999;
}
In this case, the menu may still be clipped by the card. The fix may be changing the overflow behavior, moving the dropdown outside the clipped container, or rendering the overlay in a higher-level layer. Increasing z-index alone will not solve clipping.
This distinction is important in dashboards, ecommerce menus, and card-based interfaces. If the element is cut at the parent edge, inspect overflow first. If it is covered by another element, inspect stacking context and z-index.
This simple check saves time because clipping and stacking bugs often look similar at first glance.
After that, compare the ancestors of both overlapping elements, not only the two elements themselves.
Z Index and Source Order
When elements have the same stacking level, source order can decide which appears on top. Later elements in the HTML can paint above earlier elements in some normal stacking situations.
This is why changing z-index is not always necessary. Sometimes the natural document order already controls the stack. Use z-index when an intentional layer system is needed.
Debugging Z Index
When z-index does not work, do not immediately increase the number. First check whether the element is positioned, whether it is inside a stacking context, whether an ancestor clips it with overflow, and whether another element belongs to a higher stacking context.
- Check position and z-index on the element.
- Inspect ancestors for transform, opacity, filter, isolation, and z-index.
- Check overflow clipping on parent elements.
- Compare stacking contexts, not only numbers.
- Use browser developer tools to inspect computed styles.
- Create a named z-index scale for large projects.
Common Z Index Mistakes
- Using huge z-index values without understanding stacking context.
- Forgetting that transform can create a stacking context.
- Trying to fix overflow clipping with z-index.
- Using negative z-index and hiding elements behind backgrounds.
- Using random z-index numbers across a project.
- Expecting z-index to matter when elements do not overlap.
Z index in CSS FAQ
What does z-index do in CSS?
z-index controls stacking order when elements overlap.
Why is z-index not working?
Common causes include missing positioning, stacking contexts, overflow clipping, or comparing elements in different stacking groups.
Can z-index be negative?
Yes. Negative z-index values are allowed, but they can place elements behind parent backgrounds or make them hard to interact with.
Should I use z-index 999999?
Usually no. A named z-index scale is cleaner and easier to maintain than huge random values.
Continue learning CSS in order
Follow the topic sequence with the previous and next lesson.