Handling z-index

Avatar of Chris Coyier
Chris Coyier on (Updated on )

DigitalOcean provides cloud products for every stage of your journey. Get started with $200 in free credit!

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.

That “A” better appear on top of the modal, which needs to appear above any characters, which need to appear above the background layer…

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:

  1. They are all declared together
  2. 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!


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 stock photography metaphor!

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.