What :is() the deal? Simplifying CSS with the :is() pseudo-class

Lucius VanSlyke
Nerd For Tech
Published in
4 min readMar 7, 2021

On our journey to web-developerhood, at some point or another many of us have had to deal with the subtly maddening nature of CSS selectors. Chaining elements together to get the specific results we want can become one of those little headaches, and I’ll show you how to hopefully make it a bit less tedious with a neat trick. Feel free to follow along at my code sandbox link for a better visual aid here.

For the sake of example, say you really wanted two particular elements in your header to be a beautiful firebrick red. In our case, we want “Hello, what a wonderful day!” and “Well, let’s get started!”. In order to do that without multiple CSS rules, we would generally have to use a compound selector and do something like this:

--- HTML ---<header>
<h1>Hello, what a wonderful day!</h1>
<span>Are you ready to learn about pseudo-classes?</span>
<span><strong>Well, let's get started!</strong></span>
</header>
<section>
<span>This is another spaaaan.</span>
</section>
--- CSS ---header h1, header strong{
color: firebrick;
}

Here we are grabbing the h1 from the header tag, and because we have multiple spans throughout the page we grab the header’s strong tag in order to be specific. Although this is totally valid CSS and often quite useful, it also presents a few issues.

First and foremost, it has the potential to get quite lengthy depending on the number of selectors and level of specificity. Secondly, when chaining CSS selectors together, a single error/invalid selector will cause the entire CSS ruleset to break and fail to render.

--- CSS ---/* Oh no, your tired programmer brain made a typo in "strong" that messes up the entire rule! */ header h1, header :strong{
color: firebrick;
}
/* This is quite different than a CSS declaration error (what's inside the brackets). If we did something like seen below, everything up until the error (font-size) will still render. */header h1, header strong{
color: firebrick;
margin-bottom: 10px;
font-size: "I'm LARGE!!!!"
}

Where the :is() pseudo-class comes in, is that instead of writing our compound selectors like above, we can write this:

header :is(h1, strong){
color: firebrick
}

But what’s the difference? For a more stark comparison, imagine if the original header selector had many more descendants, it could look something like this:

/* Original Syntax */header h1, 
header strong,
header img,
header .btn,
header p {
color: firebrick;
margin-bottom: 10px;
font-size: "Hello world!!!!"
}
/* :is() Syntax, equivalent to above */header :is(h1, strong, img, .btn, p){
color: firebrick:
margin-bottom: 10px;
}

With this syntax, you only need to list the parent selector once and then provide your descendants in the brackets. Furthermore, even if you have an error in one of your descendant selectors, the rest of them will render properly.

header :is(h1, strong, :img, .btn, :p){
color: firebrick:
margin-bottom: 10px;
}
/* Even though both img and p invalid selectors, the h1, strong, and .btn class will all still function correctly. */

This doesn’t just have to be used with parents and descendants, it can also be used to group selectors on its own. I would consider this an even more practical use than above.

:is(header, .card, small) p:hover {
color: red;
}
/* code below is equivalent to the code above */header p:hover,
.card p:hover,
small p:hover, {
color: red;
}

Here we are saying that all p tags that are either in a header tag, within a class of card, or in a small tag will be red on hover. Essentially, the :is() function takes a selector list as its argument and groups them together, then you can assign properties as you see fit. This is a relatively new CSS pseudo-class, and is a great trick for making your pages more DRY and readable.

NOTE: One thing to remember when using the :is() syntax is selector hierarchy. Let’s say we have a card class, and we want specific selectors within this card to be green. But then we forget that we did that, and we attempt to make one of those same elements a different color. This will not work due to the selector hierarchy if one or more of the selectors is higher priority.


.card :is(.title, small){
color: green;
}
/* Because of the 'title' class in the brackets (classes have more priority than vanilla tags), the one above takes priority. */.card small{
color: blue;
}

With all of that in mind, have fun making your CSS as pretty on the inside as it is on the outside!

--

--

Lucius VanSlyke
Nerd For Tech

Lover of games, programming, and food. Consistently creating something that involves at least two of these.