Software Engineering

CSS’ z-index misunderstood

The z-index property in CSS behaves differently than I (unconsciously) always thought, I learned today. A web-application I’m working on has two CSS dropdown menu’s, that can sometimes overlap. The main menu should appear above the other menu, so I gave the main menu a higher z-index than the other menu. The container of my main menu also had a z-index, but it’s lower than the z-index of both menu’s so it doesn’t matter right? Well, apparently is does matter, in some cases.

Consider this example:

<div class="page">
    <div class="header" style="position: relative; z-index: 5;">
        <ul class="main-menu" style="position: absolute; z-index: 20;"></ul>
    <div class="content" style="position: relative; z-index: 10;">
        <ul class="other-menu" style="position: absolute; z-index: 15;"></ul>

The main menu has the highest z-index, but to my surprise it didn’t appear above the other menu. In my imagination z-index was some kind of global property that always places elements with a higher z-index above elements with a lower z-index, but it turns out to be a little bit more complicated than that. As this excellent blog post describes, z-index uses stacking contexts. Two quotes that are relevant here:

“When you introduce the position property into the mix, any positioned elements (and their children) are displayed in front of any non-positioned elements. (To say an element is “positioned” means that it has a position value other than static, e.g., relative, absolute, etc.)”


“The key to avoid getting tripped up is being able to spot when new stacking contexts are formed. If you’re setting a z-index of a billion on an element and it’s not moving forward in the stacking order, take a look up its ancestor tree and see if any of its parents form stacking contexts. If they do, your z-index of a billion isn’t going to do you any good.”

So in my case, the header div and content div form a stacking context. By giving the header div a higher z-index than the content div, it will always appear above anything that’s placed inside the content div. This works even if the content div contains a menu with a higher z-index than the header div:

<div class="page">
    <div class="header" style="position: relative; z-index: 10;">
        <ul class="main-menu" style="position: absolute; z-index: 15;"></ul>
    <div class="content" style="position: relative; z-index: 5;">
        <ul class="other-menu" style="position: absolute; z-index: 20;"></ul>


Previous Post Next Post

You Might Also Like

No Comments

Leave a Reply