DEV Community

Cover image for What’s the highest z-index on a page (and other CSS property problems)
Paceaux
Paceaux

Posted on • Updated on • Originally published at blog.frankmtaylor.com

What’s the highest z-index on a page (and other CSS property problems)

Ever been the new person on an old project where you were trying to not make things substantially worse? Maybe you need to position an element, but you don’t know what z-index value is safe to use. You don’t want to layer something to z-index: 9999 if z-index: 10 will suffice… but how do you find out what the highest z-index is?

Or, for that matter, how do you find everything that’s using opacity?

Sure, you’ve got a modern browser with great debugging tools. But they don’t make it easy for you to search by CSS properties. So I wrote a JavaScript function that can do that.

Remember the CSSOM?

I’ve written about the CSSOM in the past (CSS Object Model) and I’ll say again that it’s an under-appreciated and under-utilized feature of the web browser environment.

If you need to do something so peculiar as searching for selectors by CSS properties, this is the thing the CSSOM is good for.

It starts with the stylesheets

Let’s start by creating a new function that’ll take two arguments; queryPropName and queryPropValue. We’ll access some styleSheets and loop through them since they’re enumerable, but not an array.

function queryCSSByProperty(queryPropName, queryPropValue) {
  const styleSheets= document.styleSheets; 
  const properties = new Map(); 

  Object.values(styleSheets).forEach(styleSheet => {

  });
}
Enter fullscreen mode Exit fullscreen mode

Next, try to loop through the rules

We’ll need to wrap the interior of our loop in a try-catch because the browser may throw some restrictions at us trying to access some of the cssRules. Then we’ll loop through the rules of that styleSheet

Object.values(styleSheets).forEach(styleSheet => {
      try {
        const rules = styleSheet.cssRules; 

        Object.values(rules).forEach(rule => {
        });
      } catch (err) {
        console.log(err);
}
Enter fullscreen mode Exit fullscreen mode

Then, look for a style on the rule

Now that we’re inside of a rule inside of a stylesheet, we’re where we need to be. So now what we want to do is see if the CSS property we want is there.

First, let’s pull out some things that will be useful, like style, which will be an object that contains every possible CSS property. Let’s also grab some selectorText, which is strictly the CSS selector part of this ruleset (e.g. .someSelector > h1 > .foo )

Once we get that out, let’s be safe and check to be sure style is truthy. Not every cssRule will have a style property.

 Object.values(rules).forEach(rule => {
          const {style, selectorText} = rule;

          if (style) {

          }
});

Enter fullscreen mode Exit fullscreen mode

And if there’s a style, check if it’s the one you want

This is where some logic could probably be cleaned up.

First, let’s use the CSSOM, rather than hasOwnProperty or for–in to find out if there’s a value for our property. getPropertyValue turns out to be the perfect way to get the value off of a specific CSS property in our style.

Next, because we want an option to see search by value of a property, we have hasPropValMatch to tell us exactly that. And for right now, rather than ===, let’s use indexOf because there’s always the chance that there’s an !important floating here. It’d be better to search within the string rather than assume it’s a pure equality. We’ll probably need more robust matching in the future.

Finally, we check if our queryPropValue is there (because, after all, maybe you’re just interested in z-index, not z-index: 10 ). If it is, let’s set a value to our map.

We’ll make the key of our item the CSS selector, which is the selectorText. Then we’ll make the value a mashup of the property name and the property value. It won’t be a duplicate of what’s written in the actual stylesheet — just what’s important for search purposes.

if (style) {
        const propertyValue = style.getPropertyValue(queryPropName);
        const hasPropValMatch = queryPropValue && propertyValue.indexOf(queryPropValue) !== -1;

        if (queryPropValue && hasPropValMatch) {
          properties.set(selectorText, `${queryPropName}:${propertyValue}`);
        }

        if (!queryPropValue && propertyValue) properties.set(selectorText, `${queryPropName}:${propertyValue}`);
}
Enter fullscreen mode Exit fullscreen mode

Finally, stitch it all together

Once we’ve done all this, let’s make sure that we return those properties we’re setting values in:

function queryCSSByProperty(queryPropName, queryPropValue) {
  const styleSheets= document.styleSheets; 
  const properties = new Map();

  if (!queryPropName) return properties;

  Object.values(styleSheets).forEach(styleSheet => {

    try {
      const rules = styleSheet.cssRules;

        Object.values(rules).forEach(rule => {
          const {style, selectorText} = rule;

          if (style) {
            const propertyValue = style.getPropertyValue(queryPropName);
            const hasPropValMatch = queryPropValue && propertyValue.indexOf(queryPropValue) !== -1;

            if (queryPropValue && hasPropValMatch) {
              properties.set(selectorText, `${queryPropName}:${propertyValue}`);
            }
            if (!queryPropValue && propertyValue) properties.set(selectorText, `${queryPropName}:${propertyValue}`);
          }
      });
      } catch (err) {
        console.log(err);
      }
    });
    return properties;
}
Enter fullscreen mode Exit fullscreen mode

Final Result?

You should be able to run queryCSSByProperty('z-index') on this page and discover that there's over 60 CSS rulesets using z-index. Quite nicely though for dev.to, they're managing most of them with CSS custom properties.

A function like this will help you not be that person who’s picking random numbers out of a hat. In fact, a function like this might be a useful way to make sure your element is always lastzIndex + 1.

Of course, this could have other uses, too, beyond z-index. But you get the idea.

BTW, the final version of this is a gist, if that’s what you’re looking for.

Top comments (0)