Implementing a new z-index system with SASS

Similar to font-size and line-height, we have a lot of various z-index definitions in Discourse. If you’ve worked in CSS before, you’ll be familiar with the values we use. They range from the reasonable: 1, 10, 20, 50 to the extreme: 9999, 99999, 10000000. As you can imagine this can be easy to lose track of when you have thousands of lines of CSS (when in doubt, just add more 9s?).

After doing a bit of research (there’s some good advice from CSS-Tricks and Smashing Magazine) I settled on a system that mashes up suggestions from a few sources.

You can read the article if you want to get into the specifics of how the SASS function works, but the short of it is: we’re creating a SASS map and using a function to pull out values.

At-a-glance you can look in our variables.scss file see how things stack up:

$z-layers: (
  "max":              9999, 
  "fullscreen":       1700,
  "modal": (
    "tooltip":        1600,   
    "popover":        1500,
    "dropdown":       1400,
    "content":        1300,
    "overlay":        1200,
  "mobile-composer":  1100,
  "header":           1000,
  "tooltip":          600,
  "composer": (
      "popover":      500,
      "content":      400,
  "dropdown":         300,  
  "usercard":         200,
  "timeline":         100,
  "base":             1

You have basic values like “dropdown” and “fullscreen” but we can also nest some values for more complex stacking like within modals or the composer. The nested values don’t need to be sequential as I’ve set them (due to stacking contexts), but it makes the hierarchy clearer and works as you’d expect.

You call these values in our core CSS like this:

div {
    z-index: z("header");

or when nested, like this:

div {
    z-index: z("modal", "dropdown");

You can also do basic math as you’d expect:

div {
    z-index: z("base") + 1;

This will help us to use fewer overall values, understand the relationship between our most common values, and allows us to flexibly add values to the map… if we need to style a one-off element that doesn’t call for adding a new map value we can do something like z-index: z("base") + X;.


I believe this is merged already, right @awesomerobot?

It looks like the post highlight (not sure the correct name) has a higher z-index than a group avatar flair. It looks strange with the blue highlight covering only part of the flair. Should the flair be above the highlight? I think it was before.