The axis you cannot see
Besides width and height, boxes live on a third axis: the Z axis, running
from the screen toward you. It is depth. When two elements overlap, z-index
decides which one stays in front: the higher the number, the closer to you.
Think of a deck of cards on a table: the top card covers the ones below it.
.behind { position: absolute; z-index: 1; }
.front { position: absolute; z-index: 2; } /* covers .behind */
z-index only works with position
z-index only takes effect on positioned elements (that is, with a
position other than static: relative, absolute, fixed or
sticky). On a static element it is completely ignored.
⚠️ CLASSIC TRAP: setting z-index and forgetting the position. You
crank the number up to 9999, nothing happens, and you start questioning your
sanity. Before touching z-index, make sure the element is positioned.
.modal {
position: fixed; /* without this, the z-index would do nothing */
z-index: 100;
}
Stacking contexts (intro)
A stacking context is an independent Z "bubble". Inside it,
the children's z-index values only compete with each other, not with
elements outside. An element creates a new context when, for example:
- it has a positioned
positionand a numericz-index, or - it has
opacityless than 1, atransform, afilter, etc.
The practical consequence: a child with z-index: 9999 will never beat an
element from another bubble whose parent has a higher z-index. If a modal
"hides" behind something despite its huge z-index, the cause is almost always
a stacking context created by an ancestor.
Key idea: Z order is resolved by levels, first between bubbles and then within each one. Keep few contexts and low, orderly numbers; your future self will thank you.
That wraps up classic placement. The next step is flexbox, where you stop pushing boxes around one by one and tell the container to lay them out for you.
Examples
The red circle stays in front because of its higher z-index
<style>
.zone { position: relative; height: 80px; }
.circle {
position: absolute;
top: 10px;
width: 50px;
height: 50px;
border-radius: 50%;
}
.blue { left: 10px; background: #3b82f6; z-index: 1; }
.red { left: 35px; background: #ef4444; z-index: 2; }
</style>
<div class="zone">
<div class="circle blue"></div>
<div class="circle red"></div>
</div>