:is()

The CSS Selectors Level 4 describes the :is pseudo-class as having the same functional properties as :matches. They have the same syntax and are both able to make complex groupings of selectors easier to write.

That's where the similarities between the two stop because :is has no impact on specificity.

Syntax

:is( selector[, selector]* )

It's very similar to :matches, which we can use like this:

:matches(section, article, aside, nav) :matches(h1, h2, h3, h4, h5, h6) {
  color: #BADA55;
}

/* ... which would be the equivalent of: */
section h1, section h2, section h3, section h4, section h5, section h6, 
article h1, article h2, article h3, article h4, article h5, article h6, 
aside h1, aside h2, aside h3, aside h4, aside h5, aside h6, 
nav h1, nav h2, nav h3, nav h4, nav h5, nav h6 {
  color: #BADA55;
}

We could do the same thing with :is but it's better as a means to add more conditions to a matching case without affecting the specificity of that match. So maybe don't use it that same way, even if it is permissible.

The editor's draft of the CSS Selectors Level 4 specification notes that future :is versions may introduce a second argument that sets the level of specificity of is is applied. It mentions the default of this argument would be 0. Taking a guess here, but I assume that means that the specificity increases as the number does, sort of the same way z-index behaves.

The Same, but Different

We've talked about how :is and :matches are similar because they share the same syntax and general functionality that allows them to group selectors together.

But that's where the similarities end. When we apply :is to an element, that element's descendants are left untouched.

The same cannot be said of :matches. Take, for example, the following scenario where :matches is applied to the hover and focus states of any matching links.

a:matches(:hover, :focus) {
	color: red;
	text-decoration: none;
}

We'd expect that anything more specific and declared lower in the cascade would take precedent, but that's not the case.

a:matches(:hover, :focus) {
	color: red;
	text-decoration: none;
}

/* This will not work */
.nav a {
	color: purple;
	text-decoration: underline;
}

That makes :matches great if you want to ensure greater specificity on matched elements. Otherwise, :is is more flexible in that regard:

a:is(:hover, :focus) {
	color: red;
	text-decoration: none;
}

/* The cascade is respected and this is will work! */
.nav a {
	color: purple;
	text-decoration: underline;
}

I feel it's worth point out here that these (and any other) examples are hypothetical since browser support for :is is next to nil at the time of this writing. We'll talk more about that in a bit.

There Used to Be Another Difference

Before changes in the spec, there was a second key difference between :is and :matches in that :is could be used in combination with :not whereas :matches couldn't.

According to the previous specification:

A negation may not be nested within itself or within :matches(): :not(:not(...)) and :matches(:not(...)) are invalid.

That means this wouldn't have worked:

a:matches(:not(:hover)) {
  text-decoration: none;
}

...but this would:

a:is(:not(:hover)) {
  text-decoration: none;
}

The more recent spec that introduces :is has since removed that limitation from :matches so that difference is not longer a thing.

It's kind of nice how :is makes that read a lot more like a sentence in this context.

Browser Support

We alluded to this earlier, but :is has no browser support at the moment. It was introduced in the Editor's Draft 1 of the CSS Selectors Level 4 Specification. That means things are still getting shaped out making it a little early for browsers to rally around a concept like this.

That said, we do have great browser support in the form of :matches for the general functionality, just without the change in specificity. And, of course, :not is another pseudo-class that can assist with matching.

What's interesting to note is that :is was introduced after :matches which was introduced after :any. It's sort of like :any is being replaced by :matches which is being extended by :is Always neat to see how these things eveolve.

Related

Resources

This comment thread is closed. If you have important information to share, please contact us.
icon-anchoricon-closeicon-emailicon-linkicon-logo-staricon-menuicon-nav-guideicon-searchicon-staricon-tag