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>
    <div class="content" style="position: relative; z-index: 10;">
        <ul class="other-menu" style="position: absolute; z-index: 15;"></ul>
    </div>
</div>

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.)”

and

“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>
    <div class="content" style="position: relative; z-index: 5;">
        <ul class="other-menu" style="position: absolute; z-index: 20;"></ul>
    </div>
</div>

 

Previous Post Next Post

You Might Also Like

No Comments

Leave a Reply