CSS pseudo-classes with :where() and :is()
Tags: css, webdev, html, codepen
Published: 2022-06-21 13:02:58

If you haven't heard about the **:where()** and **:is()** pseudo-classes, don't feel bad. They were only recently introduced to most browsers. 

But they might be your new favorite thing in CSS. 

The **:where()** 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.

```
/* Selects any paragraph inside a header, main
   or footer element that is being hovered */
:where(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

/* The above is equivalent to the following */
header p:hover,
main p:hover,
footer p:hover {
  color: red;
  cursor: pointer;
}
```

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.

```
/* Selects any paragraph inside a header, main
   or footer element that is being hovered */
:is(header, main, footer) p:hover {
  color: red;
  cursor: pointer;
}

/* The above is equivalent to the following */
header p:hover,
main p:hover,
footer p:hover {
  color: red;
  cursor: pointer;
}
```

The difference between **:where()** and **:is()** is that **:where()** always has 0 specificity, whereas **:is()** takes on the specificity of the most specific selector in its arguments.

Let's understand this with an example, the difference between **:where()** and **:is()**.

```
<article>
  <h2>:is()-styled links</h2>
  <section class="is-styling">
    <p>Here is my main content. This <a href="https://mozilla.org">contains a link</a>.
  </section>

  <aside class="is-styling">
    <p>Here is my aside content. This <a href="https://developer.mozilla.org">also contains a link</a>.
  </aside>

  <footer class="is-styling">
    <p>This is my footer, also containing <a href="https://github.com/mdn">a link</a>.
  </footer>
</article>

<article>
  <h2>:where()-styled links</h2>
  <section class="where-styling">
    <p>Here is my main content. This <a href="https://mozilla.org">contains a link</a>.
  </section>

  <aside class="where-styling">
    <p>Here is my aside content. This <a href="https://developer.mozilla.org">also contains a link</a>.
  </aside>

  <footer class="where-styling">
    <p>This is my footer, also containing <a href="https://github.com/mdn">a link</a>.
  </footer>
</article>
```

```
html {
  font-family: sans-serif;
  font-size: 150%;
}

:is(section.is-styling, aside.is-styling, footer.is-styling) a {
  color: red;
}

:where(section.where-styling, aside.where-styling, footer.where-styling) a {
  color: orange;
}
```

What if, later on we want to override footer property? Let's try

```
footer a {
  color: blue;
}
```

This won't work for the red links, because the selectors inside :is() count towards the specificity of the overall selector, and class selectors have a higher specificity than element selectors.

However, selectors inside :where() have specificity 0, so the orange footer link will be overridden by our simple selector.

You can see the output and complete code here [Difference b/w :where() and :is()](https://codepen.io/bhavshashank/pen/rNJgqjr)

Also note, In CSS when using a selector list, if any of the selectors are invalid then the whole list is deemed invalid. When using :is() or :where() instead of the whole list of selectors being deemed invalid if one fails to parse, the incorrect or unsupported selector will be ignored and the others used.

Hope you find this useful.