The CSS :is() and :where() pseudo-classes

The :is() functional pseudo-class lets us write compound selectors in a more simple and short way. It takes a list of selectors as arguments and matches elements by creating different combinations of selectors at run time. For example, CSS selectors like this:

header a, .main a, #footer a {
    color: blue;
}

.main p, .main li, .main a {
    font-size: 1rem;
}

Can be written using :is() like this:

:is(header, .main, #footer) a {
    color: blue;
}

.main :is(p, li, a) {
    font-size: 1rem;
}

This will simplify more complex selectors into simple ones.

header p, header a, header li, header blockquote,
.main p, .main a, .main li, .main blockquote,
section p, section a, section li, section blockquote,
#footer p, #footer a, #footer li, #footer blockquote {
  color: blue;
}

/* similar to */

:is(header, .main, section, #footer) :is(p, a, li, blockquote) {
  color: blue;
}

Forgiving selector lists

In CSS, if we have written any invalid selector in a selector list, then the entire CSS rule becomes invalid. It won’t work for the valid selectors also. For example:

li, p, button:wrong-selector, input {
  font-size: 1.2rem;
  color: blue;
}

Here the :wrong-selector is an invalid selector. Therefore this entire CSS rule becomes invalid, and the CSS properties won’t apply to the correct selectors (li, p, input) as well.

However, this is not the same case with :is(). Here, only the invalid selectors are ignored, and the CSS is applied to all the correct ones.

:is(li, p, button:wrong-selector, input) {
  font-size: 1.2rem;
  color: blue;
}

Here, only the button:wrong-selector will be invalid, but the CSS will be applied to the other correct ones, li, p, and, input.

Specificity

In CSS, if multiple rules are present for the same selector, then the properties value is applied from the rule whose selector has higher specificity. For example:

<div class="card">
  <button id="button" class="btn">Submit</button>
</div>
/* Specificity (0,2,0) */
.card .btn {
  color: green;
}

/* Specificity (1,0,0) */
#button {
  color: blue;
}

/* Specificity of button (0,0,1) */
button, #info {
  color: black;
}

Here, color:blue will be applied to the button as #button has a specificity of 100, which is greater than the specificity values of the other two selectors, i.e., 1 and 20.

In the :is() pseudo-class, the specificity value is determined to be the same as the highest specificity in the selector list. For example:

/* Specificity (1,0,0) */
:is(button, #info) {
  color: green;
}

/* Specificity (0,1,0) */
.btn {
  color: blue;
}

Here, color:green will be applied to the button, even though .btn has higher specificity than the button selector. Let’s analyze how it happened.

The specificity of the element selector button is 1, and the id selector #info is 100. The specificity of :is() is the same as the highest specificity value in the selector list, so the specificity of :is() becomes 100 here. As the specificity of .btn is 10, which is less than 100, CSS rules with :is() selector get applied.

The :where() pseudo-class

The :where() is similar to the :is() pseudo-class. It lets us simplify CSS compound selectors. For example:

header a, .main a, #footer a {
    color: blue;
}

.main p, .main li, .main a {
    font-size: 1rem;
}

/* Similar to */

:where(header, .main, #footer) a {
    color: blue;
}

.main :where(p, li, a) {
    font-size: 1rem;
}

The only difference between :where() and :is() is that :where() always has 0 specificity, whereas :is() counts the specificity to be the same as the highest specificity value in the selector list. For example:

/* Specificity (0,0,0) */
:where(button, #info) {
  color: green;
}

/* Specificity (0,1,0) */
.btn {
  color: blue;
}

Here color:blue will be applied to the button, as the :where() selector has the specificity of 0 and .btn has 10.

Pseudo-elements with :is() and :where()

Pseudo-elements don’t work with :is() and :where(). So we should use the regular way of writing selectors while targeting pseudo-elements.

/* invalid selectors */
element:is(::before, ::after) {
  /* properties */
}

element:where(::before, ::after) {
  /* properties */
}

/* valid selector */
element::before, element::after {
  /* properties */
}

You may also like

Leave a Reply

Your email address will not be published. Required fields are marked *