Managing z-index across large sites can be a pain in the butt. CSS is hard to test, so it’s notoriously easy to make a change that ends up, for instance, hiding some important UI under who-knows-where.
If you use a CSS preprocessor, maybe we can handle it in a special way.
An Idea From Game Programming
Vertical stacking order is not only a problem for web design, it’s a major issue for game developers too. They work in even more dynamic environments where it is vitally important which things appear on top of others.

In a brief conversation with Ryan Campbell, who is digging into the world of games, he says the way it’s normally handled is a enum (kind of like a named array of constants) variable which then you reference as needed.
Here’s an example of some code he might use:
typedef enum : uint16_t {
WorldLayerGround = 100,
WorldLayerBelowCharacter = 200,
WorldLayerAboveCharacter = 400,
WorldLayerTop = 800,
WorldLayerCount = 1600
} WorldLayer;
That is defined in a file dedicated to declaring constants for the game to use. Notice how:
- They are all declared together
- There is space left between the numbers
It’s fairly common to see people number in the hundreds with z-index
in web design too. The idea being that you could slip something in between later if need be, which you couldn’t if you did 1, 2, 3, etc, because z-index
doesn’t support decimals. But rarely do you see z-index
declared in a group like that. Seems like a smart idea to me!
Grouping
The idea is that all the code that controls vertical stacking is in one place. You could just put all that stuff together.
.modal {
z-index: 9000;
}
.overlay {
z-index: 8000;
}
.header {
z-index: 7000;
}
But I’m not a huge fan of that. I don’t like duplicating selectors throughout stylesheets just for organization. Just a personal preference. When I find where a class is defined, everything that that class does is there.
Perhaps we can do the same thing but just with the values…

A z-index Partial
Perhaps the single most useful feature of preprocessors is the ability to do includes. Smush multiple files together into one output file. That means you can organize your CSS however makes sense to you, which almost surely means breaking down into small, modular bits.
Maybe you already have a variables.styl
or constants.less
or something. You could get even more modular and have a file just for managing z-index
. In SCSS, the typical naming convention for files only meant to be included start with an underscore, so we’d make a _zindex.scss
.
In that file, you’d declare variables that contain all the z-index values you use throughout the site.
$zindexModal : 9000;
$zindexOverlay : 8000;
$zindexHeader : 7000;
Then in your global set of includes for other SCSS files, you always have this available:
@import "zindex";
And use them as needed:
.header {
z-index: $zindexHeader;
}
The idea would be go absolutely whole-hog on this. Do not declare z-index anywhere without making a variable for it and placing it within the stack in the _zindex.scss
file.
Maps might be cleaner
Same idea, but using a Sass map instead of individual global variables:
$zindex: (
modal : 9000,
overlay : 8000,
dropdown : 7000,
header : 6000,
footer : 5000
);
.header {
z-index: map-get($zindex, header);
}
I think I’ll be converting sites over to this system. I don’t see any downside and plenty of upsides.
Wow, I really dig this idea, especially for large projects that multiple developers are working on. Whenever I come across a z-index issue and need to change a value I’m worried that the value I changed was set in conjunction with another element elsewhere in the site/app that I’m not aware of, and often times changing a z-index value to solve an issue just creates another issue somewhere else. It’s really easy to loose track of what values are doing what, and this would help out a lot with that. I suppose if not using this technique the very least I could do is include a comment explaining the value and what other elements it correlates to.
Thanks for the idea though, brother!
This idea is already in use in Twitter Bootstrap.
This is where I borrowed it from first as well and it’s a great system. Makes troubleshooting z-index much easier.
Great idea – I’d definitely use a map and write a function to save time typing later:
Then:
I have never seen this before, and I am fascinated!
Can you explain it to me?
What does a map do exactly?
Where did you learn about this stuff?
About 6 months ago I swapped to using sass variables for z-index and haven’t regretted the choice one bit. At first, we got some questions from our devs as to why we were creating variables for single purpose items, but when I explained the benefits of avoiding stacking conflicts, the lightbulb went off. This simply makes working with z-index pain and trouble free.
There is a typo, “Maybe ou already have a variables.styl” should be “Maybe you already have a variables.styl”
I like this idea a lot. I know Bootstrap uses this approach as well. We’ve also adopted it into our own code base at work.
If you have a documented coding style, adding a note about this technique helps other developers so you don’t find random instances of z-index not using this approach peppered throughout your code.
Awesome! I love that someone with as much influence as you has finally laid out a proposed z-index standard. Love the SASS take on it too.
I’ve been using something similar for a while that I call the “Z-Index Index”: https://github.com/danielmall/danielmallcom/blob/master/-/c/_scss/base.scss (starting on line 27)
I’ve always just used a stacking partial for this utility too but instead I use
data-order="100"
data attribute instead of a class. For me it’s a cleaner separation but it’s just a personal thing.Sounds interesting, and I can appreciate how that sort of thing could be considered the responsibility of the content layer. Can you tell us more about that?
Hate to be the one that notices this and points it out … “nortiously” ?
Sass maps…. didn’t even know they existed!
Is there a blog somewehere that has a posting like “Sass Features You Didn’t Know Existed”? haha (for real tho)
I didn’t realize Sass Maps were a thing, either. Now I’m off to learn all I can about them to determine how to clean up the Sass I currently have. Nice!
Please, RTFM. :)
Aside from the official sass docs, Hugo has some good stuff on improving your sass workflow with more advanced features: HugoGIRAUDEL.com.
I was going to say I’m surprised he hasn’t chimed in yet, but of course he has. Just farther down.
Useful information, I just wanted to comment and say how awesome Final Fantasy 3 is.
That’s FF6 btw :-). But all of them are awesome
The problem I have with z-index is that it only works for elements that are position:absolute, position:relative, or position:fixed.
How do you handle this for sites where you use z-index a lot? Just set everything to
* {position:relative}
? If so, how do you handle absolutely positioning an element in an element several levels above it? Or do you just avoid that as bad practice?Or does somebody have a Sass function that combines the above techniques with setting every element with z-index to position:relative by default?
You can’t change the existing system. z-index must always be used on positioned elements. I don’t see how that’s a problem. There are elements that still needs to be static and will not need positioning of any kind
This is how I’ve been handling z-index for the current web app I’m working on. With only 2 front-end devs, and 2 dozen+ back-end, setting up a Sass file with variables for each item that needed a z-index, and then documenting that in our pattern library has reduced issues with layering to 0.
@Fooman — this will give you an intro to Sass maps: http://benfrain.com/using-lists-with-maps-in-sass-3-3/
Thank you! Off to read.
I also never used maps but from the use in the article, I think I can take off with SASS maps already even without an article. Thanks for the link anyway. I’ll try to check it out
In the future, I could see this being done with CSS variables. Outside of current support limitations, I doubt that there is any better way of doing this.
This is the “old” syntax for CSS variables. Here is the new one:
Ok, it was nice to try and use C++11’s typed enums, but uint8_t limits the values to the [0, 255] range so…
Better luck next time?
You’re right! I corrected that to a type that could handle those numbers.
How’d you sleep last night? Good?
Makes sense to me. One thing this doesn’t address is integration of 3rd party widgets (modals, share buttons etc), which inevitably have their own z-index system going on, often using JavaScript to put themselves ‘on top’.
I guess agreeing on a standard approach now can only reduce this problem over time.
How do you deal with new stacking contexts? An element with z-index 7000 could be shown below an element with z-index 5000 because of their parents’ z-index.
More information:
http://philipwalton.com/articles/what-no-one-told-you-about-z-index/
https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context
That’s a good question. Surely the system could be expanded to accomodate. Perhaps just in how you organize the map:
Thanks for the doubt ! I’ve learned something new today due to the links you pasted inside “More information” :)
That’s exactly what I’m worried about too, Leon. Things get more complex as the stacking context changes and you’ll end up having stacking context related issues with the mentioned approach.
I rarely count my z-indexes above 3. That, of course, means that everybody involved needs to understand stacking contexts. The article that Leon mentioned is brilliant to write better styles using stacking contexts.
But I see that a lot of people here used the approach for good. I’ll keep my eyes open if it might come in handy someday.
@Mudassir: Glad to be of help! Stacking contexts can be quite nasty, but once you’ve wrapped your head around them you can use them to your advantage.
For example: hiding pseudo-elements behind their parent elements (http://nicolasgallagher.com/css-drop-shadows-without-images/).
Brilliant solution. Z-index is definitely one of those things that just lends itself to becoming messy and confusing. Anything that attempts to alleviate that problem is welcome Going to be switching to this approach I think.
Nice solution, but those z-indexes are way high. Any reason for them starting at 5000? I do prefer my z-indexes to stay under 100, personally. I see so many sites with z-indexes ranging from 0-999999, which is just a bit ridiculous.
This is great, I was not aware or mapped values in SCSS!
Great one there Chris! I begun making color palettes with Sass maps and it was a great experience. Now Z-index goes into the list as well.
Personally I would build a additional function to grab the z-index values instead of typing map-get too many times. Here’s an example of it would look like
It’s just going one more step, but I like this approach. Would be great if you guys found this useful
Awesome!
I use a similar approach. I don’t like to have these arbitrary high
z-index
numbers, and then adding new ones in between. It just gets messy after a while.Instead, I just use a list, and get its index from there:
This way I don’t have to fiddle around with any numbers, and adding a new item in the stack becomes really trivial.
Well, this sounds really nice but – as mentinoned before – this all comes down to nothing because of the concept of stack contexts in CSS. A pity, but I fear z-index remains a pain in the a**.. (which is in the nature of its design and cannot be overcome with assiting tools and technologies like Sass). I wish I’d be wrong.. :(
i’m working on a huge web app and i’m the only one on the team who’s in the CSS. This idea is huge help. Thanks. When’s your book available to order? hint hint
This sounds great for completely self-written code, but what about when using libraries that don’t want you setting z-index (like jQuery-dialogs) ?
It’s extremely rare that I have to resort to z-index for anything on nearly every site I work on. What are you guys using it for exactly?
Same here, and in the few cases where I do need to use z-indexes, properly setting the stacking context deals with it for me.
My practice is that the
z-index
of everyposition
ed ortransform
ed element to be placed above something appearing later in the document flow should be just1
or2
, and if thez-index
were local, make the local scope – which has aposition: relative
ortransform
or the like, set itsz-index: 0
. Also, the container of the whole page except for elements with globalz-index
es (well, indices) has aposition: relative; z-index: 0;
and for its globallyz-index
ed siblings, just assigning 1 or 2 is fine.Sorry for a typo.
Set the z-index of the local scope – which should have a position: relative or transform or the like – 0.
Here’s a fairly elegant solution I’ve come up with to handle complex z-indexing, basically abstracting the idea of z-index to just ‘layers’ and letting Sass do the tedious work. This gives it a more ‘designery’ approach and allows you to just list out your layers visually without explicitly declaring any z-index values. In a _config.scss:
In a _mixins.scss:
This can be used ‘between’ layers, too, should you need to ‘shim’ another set of z-indexes into place:
Result would spit out appropriately z-indexed ‘layers’ between the 1st and 2nd layers (from
$layers
).I haven’t spent much time optimizing this or extending it as it meets my needs for now, but I’m sure there’s more functionality you could add on top of this if so desired. Maybe a function to return the z-index of a layer, but I haven’t needed to go there yet.
Let me know your thoughts, Chris, I’m a long-time reader first-time poster ;)
-Mike McCormick
Here’s the output, should have included that:
And you can see I should have used this:
Rather than this: