How Does the CSS :is() Pseudo-Class Work?
The CSS :is() pseudo-class reduces code repetition and
simplifies complex selector patterns by grouping multiple selectors into
a single, clean declaration. By accepting a forgiving selector list and
adopting the specificity of its most specific argument,
:is() helps developers write DRY (Don't Repeat Yourself)
style sheets, target deeply nested elements effortlessly, and avoid
selector-breaking syntax errors.
The Problem with Traditional CSS Selectors
When writing styles for nested or varied document structures, developers often encounter repetitive selector chains. For instance, styling headings across different container elements traditionally requires explicitly listing every combination:
header h1,
header h2,
header h3,
article h1,
article h2,
article h3,
footer h1,
footer h2,
footer h3 {
color: #1a202c;
margin-bottom: 0.5rem;
}This pattern has several drawbacks:
- Verbosity: CSS files grow unnecessarily large.
- Maintenance overhead: Adding a new container or heading level requires updating multiple lines.
- High error rate: Duplication increases the chance of typos or missed selectors.
How :is() Streamlines
Groupings
The :is() pseudo-class condenses multi-branch selectors
by taking a comma-separated list of targets and applying the rule to any
matching branch.
The previous nine-selector block can be rewritten with a single line:
:is(header, article, footer) :is(h1, h2, h3) {
color: #1a202c;
margin-bottom: 0.5rem;
}You can place :is() anywhere in a selector sequence—at
the beginning, middle, or end. For example, applying hover and focus
states across interactive elements becomes significantly more
readable:
button:is(:hover, :focus-visible),
a.btn:is(:hover, :focus-visible) {
background-color: #2b6cb0;
}Specificity Rules of
:is()
A critical mechanic of :is() is how it calculates
specificity. Rather than having no specificity or taking an average,
the specificity of :is() is determined by its most
specific selector argument.
For example, consider the following selector:
:is(div, #unique-id, .regular-class) p {
color: blue;
}Even when this rule matches a paragraph inside a generic
div, the :is(...) token carries the
specificity weight of #unique-id (an ID selector). As a
result, the entire selector evaluates to [1, 0, 1] (one ID,
zero classes, one element).
Understanding this behavior ensures that styling rules do not unintentionally overpower other CSS declarations with higher cascade priority.
Forgiving Selector Parsing
In standard CSS selector lists, an invalid or unsupported selector breaks the entire rule block:
/* If the browser does not support :unsupported-pseudo, the whole block fails */
.valid-class,
:unsupported-pseudo {
display: flex;
}The :is() pseudo-class utilizes forgiving
selector list parsing. If any selector inside
:is() is unrecognized or invalid, the browser simply
ignores the invalid item and continues styling the remaining valid
selectors:
/* The rule still applies to .valid-class even if :unsupported-pseudo fails */
:is(.valid-class, :unsupported-pseudo) {
display: flex;
}This makes :is() resilient when working with
experimental features, vendor prefixes, or evolving web standards.
Practical Use Cases
- Reset and Base Styles: Apply consistent layout constraints, font styles, or list resets across elements without extensive selector lists.
- Interactive Element States: Group complex
pseudo-states like
:active,:hover, and:focus-visiblewithout repeating base class names. - Sectioning Content Styling: Target recurring
typographic elements across containers like
main,aside,nav, andsection.