Generating z-indices: a more complex situation

September 28, 2021

Tower construction

In post maintaining-z-index-properties, we've tackled the issue of generating z-indices in such a way, that we didn't have to guess z-index orders and set them on each component manually. We've all seen z-index: 9999 on a component, just because we wanted to make it appear on top of everything, but weren't sure of the highest z-index thus far.

We proposed this code solution:

$itemsByPriority: '.level-1', '.level-2', '.level-3', '.level-4';

@for $priority from 1 through length($itemsByPriority) {
  $selector: nth($itemsByPriority, $priority);

  #{$selector} {
    z-index: $priority;
  }
}

When built, this will output the following CSS:

.level-1 {
  z-index: 1;
}

.level-2 {
  z-index: 2;
}

.level-3 {
  z-index: 3;
}

.level-4 {
  z-index: 4;
}

That was mission accomplished for a simple scenario. What about media queries? Seems like this approach isn't quite on par with what more complex, modern websites have to offer.

Well, turns out there is one quick solution that can help us with that. We imagine a list of items, as proposed before, but each item has his own "media query breakpoint" / "viewport definition" assigned to it. We, for now, define two simple viewport definitions as such:

$ALL_SCREENS: 'all';
$FROM_TABLET: 'from-tablet';

Then, we can create lists of z-index orders like:

$indices-configuration: (
  '.over-from-tablet': $ALL_SCREENS,
  '.over-until-tablet': $ALL_SCREENS,
  '.over-from-tablet': $FROM_TABLET,
);

Now, we just need to adjust the index generation function to support this kind of input.

@mixin generate-indices($indices-configuration) {
  $priority: 1;

  @each $selector, $viewport in $indices-configuration {
    #{$selector} {
      @if $viewport == $ALL_SCREENS {
        z-index: $priority;
      }

      @if $viewport == $FROM_TABLET {
        @media screen and (min-width: 768px) {
          z-index: $priority;
        }
      }
    }

    $priority: $priority + 1;
  }
}

Then, we can call the function, and pass it the configuration of z-indices as the input:

@include generate-indices($indices-configuration);

That should output the CSS like:

.over-from-tablet {
  z-index: 1;
}

.over-until-tablet {
  z-index: 2;
}

.over-from-tablet {
  @media screen and (min-width: 768px) {
    z-index: 3;
  }
}

That solves all of our special cases. Of course, for the simplicity of this tutorial, we've only created two viewport configurations. We could add any configuration we want and make this as complex as needed.