There is a lot of hype on the :is()
pseudo-selector lately, probably because now that Safari 14 has it, it’s supported across all the major browsers. You’ve got Miriam tweeting about it, Kevin Powell doing a video, Šime getting it into the Web Platform News, and Robin mentioning it. Bramus really puts a point on it with these “three important facts”:
1. The selector list of
:is()
is forgiving
2. The specificity of:is()
is that of its most specific argument
3.:is()
does not work with pseudo-element selectors (for now)
Plus, of course, it’s main functionality which is making otherwise rather verbose, complex, and error-prone selectors easier to write. The specificity thing is extra-interesting. Miriam notes some trickery you could do with it, like juicing up specificity without actually selecting anything.
Say you wanted to use the .button
class to select, but give it a ton of specificity
:is(.button, #increase#specificity) {
/* specificity is now (0, 1, 0, 0) instead of (0, 0, 1, 0)
}
I’ve done silly stuff like this in the past:
.button.button.button {
/* forcing the selector to be (0, 0, 3, 0) instead of (0, 0, 1, 0) */
/* doesn't actually require element to have three button classes lol */
}
The :is()
trick seems a little more understandable to me.
But what if you want to go the other way with specificity and lower it instead? Well, that’s the whole point of the :where()
pseudo-selector. Functionally, it’s exactly the same as :is()
. You give it a comma-separated list of things to select as part of the selector chain, and it does, with the same forgiving nature. Except, the specificity of the entire :where()
part is zero (0).
Kevin showed off an interesting gotcha with :is()
in the video:
.card :is(.title, p) {
color: red;
}
.card p {
color: yellow;
}
You might think yellow
will win out here, but the presence of .title
in that :is()
selector on top makes the specificity of that selector (0, 0, 2, 0) winning out over the (0, 0, 1, 1) below.
This is where we could consider using :where()
instead! If we were to use the :where()
pseudo-selector instead:
.card :where(.title, p) {
color: red;
}
.card p {
color: yellow;
}
Then yellow would win, because the top selector lowers to (0, 0, 1, 0) specificity, losing to the bottom selector’s (0, 0, 1, 1).
Which one should you use? Ya know what, I’m not really sure if there is super solid time-tested advice here. At least we have both options available, meaning if you get into a pickle, you’ve got tools to use. Time has taught me that keeping specificity low is generally a healthier place to be. That gives you room to override, where if you’re riding high with specificity you have fewer options. But the zero specificity of :where()
is pretty extreme and I could see that leading to confusing moments, too. So my gut is telling me you might wanna start with :is()
, unless you notice you need to mix in a higher-specificity selector; if you do, back off to :where()
.
What CSS is missing the most is PREG or PCRE patterns. Let’s imagine a div tag with I dunno, source-code class eg: div.source-code with some piece of source code in it, and than:
.. or something like that .. and only those inside ::word-match() are colored. We wouldn’t need any js highlighter ever again. Which will dramatically increase overall performance. That would be the best thing that happened to css. And something is telling me, that it is going to come in the very near future.
objectively wrong, almost zero js highlighters are as simple as “color x word this color” otherwise you’d run into all sorts pf problems like not being able to highlight interpolated strings and nested comments being the most obvious. not to mention since js highlighters already use regex there will be exactly zero performance improvement and it’d make css 100x harder to implement…
@somebody
The thing is that css can write text and characters. On screen. Can’t paint them. Really? Why. Maybe because majority of good developers are fixing and updating their node.js setup. Query selectors are already there, capable of resolving what is the first/last character and whitespace and more. It doesn’t need to be as complex as pcre, nor the imlpementation would hurt as You think. Just take a look at transitions and simple opacity. I can still remember well how much piles of js [email protected] directly was needed just for normal fade-in-out effect + to look nice on top of that. One single line of css is mimicing those piles now.
“
not to mention since js highlighters already use regex there will be exactly zero performance improvement and it’d make css 100x harder to implement…
”I know how js highlighters work. I know how to write and modify lexers, that’s my hobby. And the thing is, js should do other stuff. The less js, the better user experience. :)
Whoa! This is great! I knew about
:is()
but not about:where()
.As for where to use which of the both, there is a solid use case for
:where()
in styling forms. Consider a default style for input elements:This has, unfortunately, already the same specificity as a class. If your class-based input style ends up higher in the stylesheet somehow (think
%foo
selectors in Sass), you lose your styles:This is a very good scenario to get
:where()
into the game, then:and you have even enough leeway in the specificity left to throw in the element name for good measure.
Have you seen my 2.5 years old blog post about a simpler and more straight forward arbitrary specificity adjustment technique? I think it’s a lot more elegant than using
:is()
pseudo.https://erraticdev.blogspot.com/2018/11/css-class-selector-with-id-specificity.html