Content:
:is() and :where() are two CSS pseudo-selectors, which take comma separated lists of selectors. They can simplify your css by reducing the number of lengthy selectors required to access elements with different parents.
If you’re unfamiliar with them, take a look at our article covering :is().
Functionally, they’re very similar. So what’s the difference, and which one should you use?
Selector Specificity
The key difference between the two is the way in which they handle specificity. Specificity dictates which rules take precedence over others, when conflicting rules apply to the same element.
If you’re unfamiliar with selector specificity, check out our article to learn more.
While :where() has a specificity of 0, :is() takes the specificity of the most specific selector it contains.
Consider the following example.
:is(#main-header, header) h1 {
color: blue;
}
:where(#main-header, header) h1 {
color: red;
}
Pretty much the same setup each time, the only difference being the :is() and :where() pseudo-selectors. What colour will the resulting text be?
Well, the :is() selector has a high specificity, due to the #main-header id it contains. :where() has 0 specificity. For this reason, the colour will be blue.
For otherwise identical selectors, as in the above example, :is() will always take precedence.
Which Should I Use?
Really, it all depends how your CSS is structured.
Using :where()
Using the less-specific :where() could prove beneficial, and it’s generally recommended to use the least specific selector required. This makes it easier to override with other rules later on.
It does weaken the specificity of the contained elements, however.
header h1 {
color: red;
}
:where(#main-header, header) h1 {
color: blue;
}
In this instance, the header h1 text will be red. The header tag is more specific than a header tag inside the :where(), due to :where() having a specificity of 0.
Using :is()
:is() has essentially the opposite effect – it can increase the specificity of the contained elements. Unlike :where(), it doesn’t always do this – it depends what’s inside.
:is(#main-header, header) h1 {
color: blue;
}
header h1 {
color: red;
}
In this example, the text will be blue.
At first glance, you might assume the text would be red. The :is() selector is equivalent to writing header h1, after all.
However, the :is() pseudo-selector also contains an id, giving :is() the same specificity as an id. This applies regardless of the type of element it’s working on.
As a result, header inside the :is() is treated like an id. For this reason, the bottom statement is unable to override the top one.
There are cases where this behaviour can be useful – but if you’re not careful, it can lead to confusion.