This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the CSS-and-design category.
Last Updated: 2024-11-21
The key to understanding z-index is to understand stacking contexts - essentially this means that there are different contexts within which z-index is active (akin to groups in photoshop or figma) and z-indexes internal to these groups cannot interact outside of these groups.
Thus "We shouldn't think of z-index purely as a way to change an element's order. We should also think of it as a way to form a group around that element's children. z-index won't work unless a group is formed." - Josh Comeau
Check out this CodePen example
You'll see there are two stacking contexts:
header
and main
)main
(with div
and p
)Even if you set the div child of main's z-index to infinity, it will appear under the header
, at least so long as the
header
has a higher z-index than that div's container, main
.
Reducing stacking contexts too A fix for this, that is almost Xen in its nature, is to remove the z-index
on main
,
thereby turning what was once two stacking contexts into a single stacking contexts where the z-indexes can interact.
However this won't help you at all if you need to position the parent element (main
) too and cannot afford to remove
its z-index
.
You can change element ordering by adding position: relative
to an element. It will appear above non-positioned
elements even if these are later in the HTML.
See CodePen
Add both position and z-index styles
.over {
position: relative; /* or absolute or fixed or sticky */
z-index: 1
}
In general, z-index only works with "positioned" elements (elements that set position to something other than the default static
) But the Flexbox specification adds an exception: flex children can use z-index
even if they're statically-positioned.
E.g. here - with no position in side and just display flex
in the wrapper, zIndex works.
<style>
.wrapper {
display: flex;
}
.second.box {
z-index: 1;
background: hotpink;
margin-top: 20px;
margin-left: -20px;
margin-right: -20px;
}
</style>
<div class="wrapper">
<div class="first box"></div>
<div class="second box"></div>
<div class="third box"></div>
</div>
If two positioned elements overlap without a z-index specified, the element positioned last in the HTML code will be shown on top. source
position: relative
or position: absolute
with z-index
opacity
to a value less than 1fixed
or sticky
: no z-index
is needed for these values!display: flex
or display: grid
containerisolation: isolate
(More on this soon!)Sometimes the problem is not z-index at all - it is clipping. Try modifying (or removing) overflow
properties to see if that helps.
Try out the isolation
property. It allows you to seal off components from z-Index interactions elsewhere - but without
you needing even change away from position static. The key problem it solves is that normally when you set a zIndex
on
something to create a stack context, you are also roped into choosing a number for your zIndex
and this has
interaction effects with sibling and parent elements or your chunck of code. See
here
You might use apply this property to the parent wrapper , then reverse actual z-index
values for internally.
.wrapper {
isolation: isolate;
}
There are chrome extensions to debug stacking contexts - e.g. this