:is() and :where()

Collapse repetitive selector lists into one and learn why :where() has zero specificity.

Ever written something like header h1, header h2, header h3 { ... } and felt your soul leave your body? :is() and :where() are the cure. Both take a list of selectors and match if any of them match.

/* Before */
header h1, header h2, header h3 { margin: 0; }

/* After */
header :is(h1, h2, h3) { margin: 0; }

The one difference that matters

They look identical, but their specificity behaves in opposite ways:

  • :is() takes the specificity of its most specific argument. So :is(#id, p) is as heavy as an ID.
  • :where() always has zero specificity, no matter what you put inside it.

That zero-specificity property makes :where() the perfect tool for authoring defaults and resets that anyone can override with a plain class — no specificity arms race, no !important.

Example

Try it yourself
Loading editor…
Press Run to see the result.

When to use it

  • A developer collapses six repeated heading selectors into one :is(h1, h2, h3, h4, h5, h6) rule to apply shared font settings.
  • A developer uses :where(.card, .panel, .modal) to apply shared base styles with zero specificity so component overrides remain easy.
  • A designer uses :is(.dark-theme, .high-contrast) :is(h1, h2) to apply heading colors for two theme variations in one concise rule.

More examples

:is() collapses heading selector list

Uses :is() to apply shared heading styles without repeating a six-element selector list.

Example Β· css
/* Without :is() β€” repeated 6 times */
/* h1, h2, h3, h4, h5, h6 { font-family: ...; } */

:is(h1, h2, h3, h4, h5, h6) {
  font-family: Georgia, serif;
  color: #1a1a2e;
  line-height: 1.2;
}

:where() for zero-specificity base

Applies shared base styles using :where() so its zero specificity never blocks component-level overrides.

Example Β· css
/* :where() adds 0 specificity β€” any class overrides it easily */
:where(.card, .panel, .widget) {
  background: #fff;
  border: 1px solid #eee;
  border-radius: 8px;
  padding: 20px;
}

/* This override wins even though it's less verbose */
.card { border-color: #2965f1; }

:is() for nested theme selectors

Combines :is() at two levels to apply dark-theme heading and body colors for two different theme attribute conventions.

Example Β· css
:is(.dark-theme, [data-theme='dark']) :is(h1, h2, h3) {
  color: #e0e0ff;
}
:is(.dark-theme, [data-theme='dark']) p {
  color: #ccc;
}

Discussion

  • Be the first to comment on this lesson.
:is() and :where() β€” CSS | SoundsCode