In 2014, Jackie Balzer wrote an excellent piece for Smashing Magazine on using Sass to automatically manage the z-indexes of elements using lists.

I've been using this technique since an ex-colleague introduced me to it in early 2015, but the disconnect between maintaining multiple lists was starting to bug me.

So, I've come up with a variation which uses Sass maps and lists instead, and allows me to clearly see the hierarchy of the different elements.

The Sass function

  @function z-index($key1, $key2: null) {
    $map: $z-indexes;
    $found-index: null;

    @if (map-has-key($map, $key1)) {
        $found-index: index(map-keys($map), $key1);

        @if ($key2) {
            $map: map-get($map, $key1);
            $found-index: index($map, $key2);
        }
    }

    @return $found-index;
}

@function z($key1, $key2: null) {
    @return z-index($key1, $key2);
}

Our CSS

Then, we set up a $z-indexes map like so:

  $z-indexes: (
    main: (
        foo,
        bar,
        tooltip
    ),
    header: (),
    modal: ()
);

and we can use it with:

  /* .header */
.header { z-index: z(header); }

/* .main elements */
.main { z-index: z(main); }
.foo { z-index: z(main, foo); }
.bar { z-index: z(main, bar); }
.tooltip { z-index: z(main, tooltip); }

/* .modal */
.modal { z-index: z(modal); }

which results in:

  /* .header */
.header { z-index: 2; }

/* .main elements */
.main { z-index: 1; }
.foo { z-index: 1; }
.bar { z-index: 2; }
.tooltip { z-index: 3; }

/* .modal */
.modal { z-index: 3; }

In this example, nothing within .main will ever be able to be above .header, and .modal sits atop everything.

Basically, you'll never have z-index conflicts again \o/

Taking it further

If you didn't want to be limited to 2 levels of nesting, this recursive z-index() version allows you to use as many levels as you like, with every level except the last being a map.