Reduce Selector Repetition with CSS :is() and :where()
Problem
Applying similar styles to multiple elements requires listing out selectors repeatedly:
.article h1,
.article h2,
.article h3,
.article h4 {
color: #333;
line-height: 1.4;
}
This gets tedious fast, especially with nested contexts.
Solution
:is() lets you group selector lists:
.article :is(h1, h2, h3, h4) {
color: #333;
line-height: 1.4;
}
/* Group both sides */
:is(.article, .sidebar) :is(h1, h2, h3, h4) {
line-height: 1.4;
}
:where() has the same syntax but always has zero specificity:
/* :is() - takes the highest specificity argument */
:is(.class, #id) p { } /* specificity: (1,0,1) */
/* :where() - always zero specificity */
:where(.class, #id) p { } /* specificity: (0,0,1) */
This makes :where() ideal for default styles that should be easy to override:
/* Base styles - easily overridable */
:where(.btn) {
padding: 8px 16px;
border-radius: 4px;
}
/* Simple class override works */
.my-btn {
padding: 12px 24px;
}
Key Points
- Both
:is()and:where()group selector lists to reduce repetition :is()adopts the highest specificity among its arguments:where()always contributes zero specificity, making overrides easy- Use
:where()for resets/libraries,:is()for component styles