Stacking contexts

If you've ever run into an issue with z-index not working as you expect, there's a good chance it's because of stacking contexts.

The browser will stack elements based on their order in the DOM and their z-index. But it also groups elements into stacking contexts. These are groups of elements that the browser treats as a single unit.

If two elements are in different stacking contexts, adjusting their z-index will not change how they stack. You have to adjust how their stacking contexts are stacking:

<body>
<!-- First stacking context -->
<div class="stacking-context">
<div id="a"></div>
<div id="b"></div>
</div>
<!-- Second stacking context -->
<div class="stacking-context">
<div id="c"></div>
<div id="d"></div>
</div>
</body>
<style>
/* These styles won't change anything */
#a { z-index: 1; }
#c { z-index: 2; }
#b { z-index: 3; }
#d { z-index: 4; }
</style>

Because the second stacking context is above the first, we cannot get # a to be above #c. The stacking contexts overrule no matter how hard we try with z-index or anything else.

However, if we change the z-index of the stacking contexts, we can get # a' and #bto appear above#cand# d`.

If we wanted to order them #a, #c, #b, #d, we'd have to change the HTML structure and move them all in to the same stacking context:

<body>
<!-- A regular div -->
<div>
<div id="a"></div>
<div id="b"></div>
</div>
<!-- Nothing special about this div -->
<div>
<div id="c"></div>
<div id="d"></div>
</div>
</body>
<style>
/* These will change the visual hierarchy */
#a { z-index: 1; }
#c { z-index: 2; }
#b { z-index: 3; }
#d { z-index: 4; }
</style>

You know a bit about stacking contexts, but what causes them, and how can you control them?

Unfortunately, the rules for creating them are not that straightforward, but well worth learning.