blense.
HomeFrontendCodeAINewsGuidesCheatsheetsAbout

Technology decoded, always.

A curated read on AI, product, and the culture behind the code. No noise, no hype.

blense.

Technology with focus. Stories about what innovation really changes.

Sections

FrontendArtificial IntelligenceCode & DevTech News

Blense

AboutRSSPrivacy policyTermsCookies
© 2026 Blense · blense.fun
Frontend

CSS :where() and :is(): Specificity, Resets, and Maintainability

Many developers overlook the CSS pseudo-classes :where() and :is(), seeing them as "syntax sugar". This article reveals how crucial they are for solving specificity chaos, enabling you to create scalable and maintainable CSS. Understand the difference and apply them in resets, components, and design systems.

Gby Genildo SouzaMar 236 min read
CSS :where() and :is(): Specificity, Resets, and Maintainability

Have you ever written the same CSS block three times, only changing the selector? That's exactly the pain that :is() and :where() solve — and the difference between the two is more important than it seems.

Does this CSS look familiar to you:

TEXT
header a,footer a,nav a {  color: blue;  text-decoration: none;}

Repeating the same rule for three different contexts. Now imagine you have ten contexts. And each one has three state variations — :hover, :focus, :visited. The CSS file turns into a phone book.

Modern CSS has an answer for this. Two, actually — and they look the same but behave differently in a detail that will save you from subtle bugs.

:is() — group selectors without repetition

The :is() accepts a list of selectors and applies the style to any one that matches. The block above becomes:

TEXT
:is(header, footer, nav) a {  color: blue;  text-decoration: none;}

One line, same result. The browser interprets this exactly like the repeated version — semantically they are equivalent.

It gets more interesting when you combine it with pseudo-classes:

TEXT
/* Before — repeating for each state */button:hover,button:focus,button:active {  background: darkblue;}/* After — clean */button:is(:hover, :focus, :active) {  background: darkblue;}

Or to style headings all at once:

The elite dev's arsenal.
Tailwind CSS v4: A Complete Guide to the New Rewrite and Performance16 minCSS Animations: How to Build Performant, Professional Interfaces Without Messy Code17 minMicrofrontends with Angular and Nx: what nobody tells you15 minJavaScript Event Loop: The Heart of Non-Blocking Concurrency — Revisited in 20256 min
TEXT
/* All headings within article */article :is(h1, h2, h3, h4) {  font-family: Georgia, serif;  line-height: 1.3;}

:where() — identical, but without specificity weight

Here lies the difference that matters.

Minimalist flat design, technical diagram, clean vector illustration, dark theme, professional tech blog style. A comparison showing CSS specificity. Left side: A block representing ':is()' with a large 'S' (Specificity) icon and an arrow pointing from a sub-element (e.g., '#id') to the main block, indicating 'Inherits highest specificity'. Right side: A block representing ':where()' with a '0' icon, indicating 'Zero Specificity'. Use different colored shapes for specificity levels (e.g., red for high, green for zero). NOT include text, explain concepts visually.

Specificity in CSS is the scoring system that decides which rule wins when two contradict each other. An ID selector is worth more than a class, which is worth more than a tag. When you use :is(), the specificity of the strongest selector inside the parentheses propagates to the entire rule.

TEXT
/* :is() inherits the specificity of #header — high */:is(#header, .nav, footer) a {  color: blue;}/* ↑ this selector has ID specificity   because of #header, even if the element   is .nav or footer */

The :where() works the same in behavior — but it has zero specificity. Always. No matter what you put inside.

TEXT
/* :where() — zero specificity */:where(#header, .nav, footer) a {  color: blue;}/* ↑ easy to override — any class   or tag selector already wins */

In practice, this means that :where() is ideal for base styles and resets — you define them without locking in the developer who will customize them later.

Minimalist flat design, technical diagram, clean vector illustration, dark theme, professional tech blog style. A side-by-side comparison illustrating CSS rule overriding. Left side: 'Problem with :is()'. Show a base rule (e.g., a gray rectangle for 'color: gray') defined using ':is()' with a large 'S' (specificity) icon, blocking a subsequent, simpler rule (e.g., a black rectangle for 'color: black') represented by a smaller 'S' (specificity) icon, with a crossed-out arrow indicating failure to override. Right side: 'Solution with :where()'. Show a base rule (gray rectangle) defined using ':where()' with a '0' (zero specificity) icon, and a subsequent, simpler rule (black rectangle) represented by a small 'S' (specificity) icon successfully overriding it, with a checkmark. NOT include text, explain concepts visually.

The real-world difference

Problem with :is()
TEXT
/* base.css */:is(article, section) p {  color: gray;}/* theme.css — will not work */p {  color: black;}/* :is(article, section) p has   higher specificity than p */
Solution with :where()
TEXT
/* base.css */:where(article, section) p {  color: gray;}/* theme.css — works */p {  color: black;}/* :where() has zero specificity   any p wins in an override */
ℹ️

Modern CSS resets use :where() for this reason. Tailwind, Open Props, and several popular resets use :where() to define base styles that never lock in the developer. The intention is: "this is the default, but anything you write easily overrides it."

An example that combines both

In a design system, you would use both in different layers:

TEXT
/* Base layer — :where() to avoid locking anyone in */:where(h1, h2, h3, h4, h5, h6) {  margin: 0 0 0.5em;  line-height: 1.2;}/* Component layer — :is() for specific contexts */.card :is(h2, h3) {  font-size: 1.25rem;  color: var(--color-heading);}/* Interactive states — :is() because weight matters */.btn:is(:hover, :focus-visible) {  outline: 2px solid currentColor;  outline-offset: 2px;}
⚠️

Be careful with invalid selectors inside :is(). If you place an invalid selector in a comma-separated list in traditional CSS, the entire rule is ignored. With :is() and :where(), invalid selectors are silently discarded — the others continue to work. This is an advantage, but it can hide typos.

What you should take away from this
  • 1:is() groups selectors and inherits the specificity of the strongest one in the list.
  • 2:where() does the same but with zero specificity — always overridable.
  • 3Use :where() in resets and base styles that should not lock in customization.
  • 4Use :is() in components and interactive states where specificity matters.
  • 5Both eliminate selector repetition — your CSS becomes smaller and more readable.
  • 6Browser support: all modern browsers. No compatibility concerns.
Featured
Want to dive deeper into this topic?

If you want to explore this topic from another angle, I've curated related readings with practical examples and applications.

Explore

#CSS#Tailwind

The elite dev's arsenal.

Stop Using useMemo Wrong: A Practical Guide to React Performance
Frontend

Stop Using useMemo Wrong: A Practical Guide to React Performance

Master React useMemo with this guide. Learn when to memoize, how to fix dependency array bugs, and why over-optimization can hurt your performance.

Genildo Souza · Jul 8 · 14 min
CSS Animations: How to Build Performant, Professional Interfaces Without Messy Code
Frontend

CSS Animations: How to Build Performant, Professional Interfaces Without Messy Code

Bring your web interfaces to life. Learn when to use CSS transitions versus keyframes and how to optimize your animations for peak performance.

Genildo Souza · Jul 4 · 17 min
Angular Micro-frontends: How to Scale Large Applications and Eliminate Monolithic Build Times with Module Federation
Frontend

Angular Micro-frontends: How to Scale Large Applications and Eliminate Monolithic Build Times with Module Federation

Discover how to break down large Angular monoliths using Module Federation to enable independent deployments and seamless team scaling.

Genildo Souza · Jun 21 · 10 min
In this article
  • :is() — group selectors without repetition
  • :where() — identical, but without specificity weight
  • The real-world difference
  • An example that combines both