CSS Pseudo-classes- :is() and :where() explained

CSS Pseudo-classes- :is() and :where() explained

Cascading Style Sheets (CSS) allows us to style web pages and provides a feature known as pseudo-class. This pseudo-class is a keyword used to target and style selectors based on certain conditions. For example, you can use the :visited() pseudo-class to apply styles to links a user has clicked on.

The is() pseudo-class

According to MDN, the :is() CSS pseudo-class function takes a selector list as its argument and selects any element that can be selected by one of the selectors in that list. This is useful for writing large selectors in a more compact form.

Simply, the is() pseudo-class is a way to group selectors and apply matching styles to these selectors.

Take a look at the code below, in the body of the HTML(HyperText Markup Language), there is a <div> with a class container that contains a <p>, another <div> and a <span> element.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>:is() Pseudo-selector Demo</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <p>This is a paragraph.</p>
        <div class="box">This is a box.</div>
        <span>This is a span.</span>
    </div>
</body>
</html>

Let's say we want to give the same colour to each of the elements in the parent <div> one way to style this is shown below;

.container p,
.container .box,
.container span {
    color: red;
}

You can go to this Codepen to see the live demo of the code.

Now, while there is absolutely nothing wrong with this styling approach, it might become somewhat lengthy and difficult to read if there were more nested elements in the parent <div>, or if you had multiple selectors you want to give the same styles.

This is where is() comes in. Rather than separating the selectors as we did above, we can just put them all inside of the is() pseudo-class. This is demonstrated below;

/* Using :is() pseudo-selector to select many elements at once */
.container :is(p, .box, span) {
    color: red;
}

The colour red would be applied to all selectors wrapped in the parentheses.

The forgiving behaviour of is()

.container p,
.container .box,
.container span,
.container .1a  {
    background-color: red;
}

This code above would throw an error and the background-color style would not reflect in the browser. This is because CSS doesn't allow for numbers to begin class names making the whole style invalid, which could be frustrating and hard to debug.

The is() pseudo-class, however, is forgiving. This means that if one of the selectors is invalid, it would apply the styles.

:is() specificity behaviour

Specificity determines what CSS styling takes priority when multiple rules target the same elements.

In the context of :is(), the most specific selector inside it determines the overall specificity. Unlike regular CSS where specificity is calculated based on the number and type of selectors, :is() does not sum up specificities. It just takes the highest one.

According to the CSS4 Working Draft,

The specificity of the :is() pseudo-class is replaced by the specificity of its most specific argument. Thus, a selector written with :is() does not necessarily have equivalent specificity to the equivalent selector written without :is()

Suppose you have this code

.container p,
.container .box{ 
    color: blue; 
}

.container :is(p, .box) {
 color: red; 
}

Here, the colour of the <p> inside the "container" class would be red because .container :is(p) has higher specificity than .container p.

:where()

According to MDN, the :where() function takes a selector list as its argument, and selects any element that can be selected by one of the selectors in that list.

This is similar to the is() and is used in the same way. The difference, however, lies in the specificity. While we have explained how the specificity of takes precedence, where has zero specificity.

If we were to style the HTML file we used previously, the CSS would look like this;

.container p,
.container .box{ 
    color: green; 
}

.container :where(p, .box) {
 color: red; 
}

You would expect the colour of <p> would be red since the styles come after. However, since we are using where and it has zero specificity, the colour would be green instead.

Useful Resources

To learn more about these pseudo-classes and further deepen your knowledge by finding out more use cases, you can click on any of the links below;

Conclusion

These pseudo-classes are two valuable tools added to your CSS toolkit. Whether you're a beginner or an experienced developer, implementing these features into your workflow can enhance the efficiency and readability of your styles. Happy styling!