:is() and :where()
They shorten the same selector lists. Only one of them keeps its weight, and that is the entire choice.
These get introduced together and the examples never distinguish them, so here is the only difference that matters.
/* both of these do the same matching */
:is(h1, h2, h3) a { }
:where(h1, h2, h3) a { }
:is() takes the specificity of its heaviest argument. :where() always has a specificity of zero.
So :is(h1, #masthead) a weighs as much as an id selector, even when it matched the h1. That surprises people exactly once, usually while they are wondering why a perfectly ordinary two-class rule underneath it is losing.
:where() weighing nothing is the useful one, and the place I now reach for it every time is a defaults layer. Anything I write in a reset or a base stylesheet goes in :where(). So it applies but never fights. A single class anywhere later beats it without a !important and without anybody thinking about it.
:where(ul, ol) {
margin-block: 0;
padding-inline-start: 0;
}
The other thing both give you is forgiving parsing. In a plain selector list, one selector the browser does not understand invalidates the whole rule. Inside either of these, the unknown one is skipped and the rest still work, which is why they turn up in cross-browser workarounds.
My rule, such as it is: :where() for anything meant to be overridden, :is() for anything meant to hold.