Handling z-index with SASS
z-index is not a particularly interesting CSS property, but it is one of the most misunderstood. What seems to be a very simple concept on the surface can be maddeningly frustrating at times. This article is not about the intricacies of
z-index; Philip Walton explains the quirks better than I can in this excellent and detailed post.
It’s entirely possible to make a large website without using
z-index at all, but if you don’t have control over your HTML, use third party CSS and/or use sticky/fixed elements or modals it becomes essential.
While SASS cannot alter the behaviour of
z-index, it can be used to make it easier to manage by placing control in one place. In vanilla CSS these values are peppered through your code leading to massive numbers like
z-index: 9000; in an attempt to pull an element above another without knowing the values assigned.
This is the simplest way to use SASS to manage
z-index. It’s quick and easy to read and write, very clear as to what’s going on and allows you to match values by setting new variables with those previously defined.
I like to set the values in multiples of 10 as this allows you to set a new variable to, say,
15 if you need something to sit between existing levels.
This solution stores the values in a map and uses a function to check the value is valid and returns it if it is.
This makes your
z-index stack (arguably) more portable between projects, and I really like the syntax of calling a function with the element name as an argument to get the
While trying to use an non-existent variable will always show an error, passing a value as an argument that doesn’t appear in a map will not. Without checking if the value exists in the map first, the function will fail silently and you could end up with something like
z-index: z(unknown-element); in your CSS.
By using a list, we don’t need to define values at all. Our function finds the index of the element in the list and returns it. You can stop thinking about numbers entirely - if you need an element to sit above another in the stacking order you just need to ensure that it comes later in the list. This takes advantage of SASS not being zero indexed; The first item in the list has an index of
For a developer working alone or someone who has a high level of understanding of the lesser-used features of SASS this is a really clean and elegant solution. For less experienced developers or those more used to vanilla CSS this could cause some head-scratching.
An issue you may face is that the values returned are going to be small numbers, so if you’re fighting against some vendor CSS with typically massive
z-index values (I’m looking at you, Leaflet) you’ll need to add to your function:
A big issue with this and solution 2 is that if you are trying to enforce a rule in a linter that states that
z-index must be set using a variable, a function call will be invalid, so you’d need to turn that rule off. This means a developer could start adding arbitrary values without the linter preventing them, a scenario even more likely if your chosen solution is hard to understand for a new or time-pressed developer.
I am currently using Solution 3 in a very large project and really enjoying how little effort is required to add a new element to the stacking order. There is no vendor CSS to work with, only a handful of elements that need their index explicitly set and I am the only developer touching the CSS so the drawbacks don’t really matter to me.
Its hard to argue with Solution 1, especially if the code base is going to be edited by a lot of developers. What it lacks in elegance it makes up for in simplicity and flexibility. You can set new variables based on existing ones, error handling and linter compatibility is free and any developer with even limited SASS knowledge is going to understand it immediately making them more likely to use it.