CSS · :is() · :where() · Selektoren · Spezifität
CSS :is() und :where()
Selektoren vereinfachen und Spezifität meistern

Lange Selektorlisten mit denselben Deklarationen sind ein Wartungsproblem jedes größeren Stylesheets. CSS :is() und :where() komprimieren solche Listen zu einer einzigen Regel, mit präziser Kontrolle über die Spezifität – und mit einem Fehlertoleranzverhalten, das klassische Komma-Listen nicht haben.

10 Min. Lesezeit :is() · :where() · :not() · Spezifität · Fehlertoleranz · Browser-Support CSS Selectors Level 4 · alle modernen Browser

1. Das Problem mit langen Selektorlisten

In jedem mittelgroßen Stylesheet findet man Regeln wie h1, h2, h3, h4, h5, h6 { margin-top: 1.5rem; } oder article p, section p, aside p, main p { line-height: 1.75; }. Das ist korrekt und funktional, aber fragil: Wenn ein neues Element zur Liste hinzugefügt werden soll, muss jede solche Regel gefunden und erweitert werden. Wenn ein Selektor in der Liste ungültig ist, ignoriert der Browser in klassischen Komma-Listen die gesamte Regel – auch alle anderen gültigen Selektoren in derselben Liste. Das ist das Fehlerbehandlungsmodell für klassische CSS-Selektorlisten.

CSS :is() und CSS :where() sind die modernen Antworten auf dieses Wartungsproblem. Beide Funktionen nehmen eine Selektorliste als Argument und matchen jedes Element, das auf einen der enthaltenen Selektoren passt. Der entscheidende Unterschied zu einer normalen Komma-Liste liegt in drei Bereichen: der Spezifitätsberechnung, dem Fehlertoleranzverhalten bei ungültigen Selektoren und der Kombinierbarkeit mit anderen Pseudo-Klassen. Diese drei Eigenschaften machen CSS :is() und CSS :where() zu einem fundamentalen Werkzeug moderner CSS-Architektur.

Das Konzept wurde ursprünglich als :matches() in CSS Selectors Level 4 eingeführt und von Safari früh implementiert. Die endgültigen Bezeichnungen :is() und :where() wurden standardisiert, nachdem klar wurde, dass zwei Varianten mit unterschiedlichem Spezifitätsverhalten nötig sind – eine, die die Spezifität der Argumente übernimmt, und eine, die immer Spezifität null hat.

2. CSS :is() – Syntax und Grundverhalten

CSS :is() akzeptiert eine durch Kommas getrennte Selektorliste und matcht jedes Element, das auf mindestens einen der angegebenen Selektoren passt. Die Syntax :is(h1, h2, h3) ist funktional äquivalent zu h1, h2, h3 in einer Kommaliste – mit dem wesentlichen Unterschied, dass die Spezifität von :is() die des spezifischsten Arguments in der Liste ist. Das bedeutet: :is(#id, .class, h1) hat die Spezifität einer ID, weil #id der spezifischste Selektor in der Liste ist.

Der wichtigste Anwendungsfall für CSS :is() ist die Vereinfachung von Selektoren, die denselben Ancestor in verschiedenen Kontexten kombinieren. Statt nav a, header a, footer a schreibt man :is(nav, header, footer) a. Statt article h1, article h2, article h3 schreibt man article :is(h1, h2, h3). Das ist nicht nur kürzer, sondern auch semantisch klarer: die Intention des Selektors ist sofort lesbar, ohne dass man die gemeinsame Struktur mehrerer Selektoren mental rekonstruieren muss.

/* CSS :is() — reducing repetitive selector lists */

/* Before :is(): verbose repetition */
article h1,
article h2,
article h3,
article h4 {
  font-weight: 700;
  color: #1e1b4b;
}

/* After :is(): single readable rule */
article :is(h1, h2, h3, h4) {
  font-weight: 700;
  color: #1e1b4b;
}

/* Combining ancestors with :is() */
:is(nav, header, .site-menu) a {
  color: #4a1d96;
  text-decoration: none;
}
:is(nav, header, .site-menu) a:hover {
  color: #7c3aed;
  text-decoration: underline;
}

/* Nested headings in any content area */
:is(article, section, .content-block) :is(h2, h3) {
  margin-top: 2rem;
  margin-bottom: 0.75rem;
  line-height: 1.25;
}

3. CSS :where() – Spezifität auf null setzen

CSS :where() verhält sich im Matching identisch zu CSS :is() – es matcht dasselbe Element bei denselben Argumenten. Der einzige und entscheidende Unterschied: die Spezifität von :where() ist immer null, unabhängig davon, wie spezifisch die Selektoren im Argument sind. :where(#id, .class, h1) a hat die Spezifität von a allein, weil der :where()-Teil nichts zur Spezifität beiträgt. Das macht CSS :where() zum idealen Werkzeug für Reset-Stylesheets, Base-Styles und Design-System-Grundlagen.

Der Nutzen wird klar, wenn man über die Cascade nachdenkt: Eine Regel in einem Reset-Stylesheet soll überschreibbar sein, ohne dass Entwickler hohe Spezifität in ihren Komponenten-Styles brauchen. Wenn das Reset :where(h1, h2, h3) { margin: 0; } verwendet, hat diese Regel Spezifität null und kann durch jede Klassen-Regel überschrieben werden, ohne Spezifitätskriege zu riskieren. Das ist das Designprinzip hinter modernen CSS-Resets wie dem von Andy Bell – alle Base-Styles mit CSS :where(), damit Konsumenten volle Kontrolle behalten.

Ein konkretes Beispiel: Tailwind CSS und andere Utility-First-Frameworks kämpfen regelmäßig mit Spezifitätsproblemen, wenn globale Base-Styles und Utility-Klassen aufeinandertreffen. Würden alle Base-Styles mit CSS :where() gesetzt, hätten Utility-Klassen immer Vorrang, da selbst eine einfache Klassenregel eine höhere Spezifität als null hat. Das löst eines der häufigsten Konflikte in solchen Projekten ohne zusätzliche Workarounds.

4. Spezifität im Detail: :is() vs. :where() vs. direkt

Das Spezifitätsmodell von CSS :is() folgt der Regel des spezifischsten Arguments: Die Spezifität der gesamten :is()-Funktion entspricht der höchsten Spezifität unter allen Selektoren in der Argumentliste. Das hat eine wichtige Konsequenz: Wenn man :is(.card, .article, #featured) schreibt, hat der gesamte Selektor ID-Spezifität – auch wenn das Element nur durch .card gematcht wird, nicht durch #featured. Das ist intuitiv für erfahrene CSS-Autoren, kann aber für andere überraschend sein.

CSS :where() hat immer Spezifität null. Das ist keine Einschränkung, sondern ein Feature: Es macht Styles explizit überschreibbar und fördert saubere Cascade-Hierarchien. :where() eignet sich für alles, was als Basis oder Default gedacht ist und niemals einen Override blockieren soll. CSS :is() eignet sich für selektiv angewendete Stile, bei denen die Spezifität der Argumente semantisch relevant ist.

/* Specificity comparison: :is(), :where(), and direct selectors */

/* Specificity: (0,1,0) — .card contributes 1 class */
.card a { color: blue; }

/* Specificity: (0,1,0) — :is() takes the max of (.card) = 1 class */
:is(.card) a { color: blue; }

/* Specificity: (0,0,0) — :where() always contributes 0 */
:where(.card) a { color: blue; }

/* Danger: mixed specificity in :is() list */
/* Entire rule has ID specificity (1,0,0) even if matched by .card */
:is(#hero, .card, .article) h2 {
  font-size: 2rem; /* overrides all class-level h2 rules */
}

/* Safe: :where() for base styles — always overridable */
:where(article, section, .prose) p {
  line-height: 1.75;
  margin-bottom: 1rem;
}

/* Override with any class — wins because :where() is specificity 0 */
.compact p {
  line-height: 1.4;
  margin-bottom: 0.5rem;
}

5. Fehlertoleranz und ungültige Selektoren

Das Fehlertoleranzverhalten ist einer der am häufigsten übersehenen Unterschiede zwischen CSS :is() und klassischen Kommalisten. In einer normalen Selektorliste wie ::-webkit-input-placeholder, ::placeholder { color: gray; } ignoriert jeder Browser die gesamte Regel, wenn er auch nur einen Selektor nicht kennt. Firefox kennt ::-webkit-input-placeholder nicht und ignoriert damit auch die valide ::placeholder-Regel. Das ist das bekannte Problem mit Vendor-Prefix-Selektoren in Kommalisten.

CSS :is() und CSS :where() verwenden eine fehlertolerante Parsing-Strategie: Ungültige Selektoren in der Argumentliste werden ignoriert, aber die gesamte Regel bleibt gültig. Das bedeutet, man kann zukünftige oder experimentelle Selektoren sicher mit etablierten mischen: :is(.supports-new-feature, :experimental-pseudo) .element funktioniert in Browsern, die :experimental-pseudo nicht kennen, trotzdem korrekt für .supports-new-feature .element. Dieses Verhalten macht schrittweise CSS-Migrationen deutlich sicherer.

Die Grenze der Fehlertoleranz liegt bei forgiving-selectors: Die Spezifikation beschreibt die Argumentlisten von CSS :is() und CSS :where() als "forgiving selector lists". Das Gegenteil – "unforgiving" – gilt für Argumente von :not() in früheren Implementierungen. Modernes :not() akzeptiert ebenfalls Selektorlisten, verhält sich aber je nach Browser-Version unterschiedlich bei ungültigen Argumenten. Das ist ein wichtiger Unterschied, der bei der :not()-Kombination berücksichtigt werden muss.

6. Kombination mit :not() und :has()

Die Kombination von CSS :is() mit :not() ist ein mächtiges Werkzeug für präzise Selektoren. :is(h1, h2, h3):not(.no-margin) matcht alle drei Überschriften-Typen, außer diejenigen mit der Klasse .no-margin. Das ist eleganter als die Alternativen h1:not(.no-margin), h2:not(.no-margin), h3:not(.no-margin). Auch die Umkehrung ist nützlich: :not(:is(h1, h2, h3)) matcht alles außer Überschriften.

Die Kombination mit :has() öffnet noch mächtigere Muster. :is(article, section):has(:is(h2, h3)) matcht alle Artikel und Sektionen, die eine h2 oder h3 enthalten. Das ist ein rein CSS-basierter "parent selector", der früher JavaScript erforderte. In Kombination erlauben CSS :is(), :where(), :not() und :has() eine Selektoren-Sprache, die strukturelle Beziehungen im Dokument direkt ausdrücken kann, ohne HTML-Klassen hinzuzufügen.

/* CSS :is() with :not() and :has() combinations */

/* All headings except those with .decorative class */
:is(h1, h2, h3, h4):not(.decorative) {
  font-family: inherit;
  font-weight: 700;
}

/* Inverse: style everything that is NOT a heading */
:not(:is(h1, h2, h3, h4, h5, h6)) {
  max-width: 70ch;
}

/* :has() + :is(): sections containing any heading level */
:is(article, section):has(:is(h2, h3)) {
  padding-top: 2rem;
  border-top: 1px solid #e2e8f0;
}

/* Links inside content areas, not inside nav or footer */
:is(article, main, .prose) a:not(:is(nav a, footer a, .btn)) {
  color: #4a1d96;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Form inputs: all text-like inputs in one rule */
:is(input[type="text"],
    input[type="email"],
    input[type="password"],
    input[type="search"],
    textarea) {
  border: 1px solid #c4b5fd;
  border-radius: 0.375rem;
  padding: 0.5rem 0.75rem;
}

7. :is() in verschachtelten Selektoren

Mit der nativen CSS-Verschachtelung (&), die inzwischen in allen modernen Browsern unterstützt wird, spielt CSS :is() eine neue Rolle. Innerhalb eines verschachtelten Blocks können Selektoren durch :is() komprimiert werden, ohne den Vorteil der Verschachtelungsstruktur aufzugeben. .card { & :is(h2, h3) { color: purple; } } ist funktional äquivalent zu .card :is(h2, h3) { color: purple; }, aber besser organisiert innerhalb der Komponentenregel.

Ein wichtiges Detail bei der Verschachtelung: Wenn man :is() mit dem impliziten & kombiniert, ergibt sich eine kompakte Schreibweise für Zustandsvarianten. .button { &:is(:hover, :focus-visible) { background: #7c3aed; } } fasst Hover- und Focus-Styles in einer Regel zusammen. Das ist lesbarer als zwei separate Verschachtelungs-Blöcke und macht deutlich, dass beide Zustände dieselben Stile erhalten sollen – eine semantisch klare Ausdrucksweise für interaktive Zustände.

8. :is(), :where() und :matches() im Vergleich

:matches() war der frühere Name für :is() in der CSS-Spezifikation und in Safari. Es ist funktional identisch und wurde durch :is() ersetzt. In Legacy-Code findet man gelegentlich noch :matches(), was in Safari 9–13 der einzige verfügbare Name war.

Funktion Spezifität Fehlertoleranz Typischer Einsatz
:is() Max. der Argumente Ja (forgiving) Komponenten, Regeln mit bekannter Spezifität
:where() Immer 0 Ja (forgiving) Resets, Base-Styles, immer überschreibbar
Kommaliste Individuell pro Selektor Nein (unforgiving) Einfache Listen ohne ungültige Selektoren
:matches() Max. der Argumente Ja Legacy-Alias für :is(), nur Safari 9–13
:not() (modern) Max. der Argumente Teilweise (browserabhängig) Ausschlüsse, Negationen

Der wichtigste praktische Unterschied zwischen CSS :is() und Kommalisten liegt bei Vendor-Prefix-Selektoren und zukunftsorientierten Selektoren. In klassischen Kommalisten muss man dieselbe Regel für jeden Prefix in einer separaten Regel wiederholen, weil eine ungültige Deklaration die gesamte Regel ungültig macht. Mit CSS :is() kann man alle Varianten in einem Argument zusammenfassen und muss die Declarations nur einmal schreiben.

9. Praxis: Design-Systeme und Reset-Stylesheets

In modernen Design-Systemen sind CSS :is() und CSS :where() aus der Toolbox nicht mehr wegzudenken. Die Basis-Typografie eines Design-Systems sollte mit CSS :where() gesetzt sein, damit Konsumenten keine Spezifitätsprobleme haben, wenn sie Varianten definieren. Komponentenspezifische Stile, die in einem bestimmten Kontext Gültigkeit haben sollen, werden mit CSS :is() kombiniert, um den Kontext klar auszudrücken.

Ein konkretes Beispiel aus einem Magento-Hyvä-Theme: Das globale Stylesheet setzt Typografie mit :where(h1, h2, h3, h4, h5, h6), sodass jede Tailwind-Klasse wie text-2xl diese Basis ohne Spezifitätsprobleme überschreiben kann. Komponentenspezifische Link-Stile innerhalb von Content-Blöcken werden mit :is(.cms-content, .blog-post, .product-description) a definiert und haben damit höhere Spezifität als allgemeine Link-Resets, aber niedrigere als explizite Modifier-Klassen.

/* CSS :is() and :where() in design system architecture */

/* Base layer: always overridable — specificity 0 */
@layer base {
  :where(h1, h2, h3, h4, h5, h6) {
    font-family: var(--font-heading);
    line-height: 1.25;
    font-weight: 700;
  }

  :where(p, li, dd) {
    line-height: 1.75;
    max-width: 70ch;
  }

  :where(a) {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
  }
}

/* Component layer: :is() — takes specificity of arguments */
@layer components {
  :is(.card, .panel, .widget) :is(h2, h3) {
    color: #1e1b4b;
    font-size: 1.25rem;
    margin-bottom: 0.5rem;
  }

  :is(.prose, .cms-content) a:not(.btn):not([class*="text-"]) {
    color: #4a1d96;
    text-decoration: underline;
  }
}

Mironsoft

CSS-Architektur, Hyvä-Themes und wartbare Stylesheet-Systeme

CSS-Selektoren, die wartbar und spezifitätssicher sind?

Wir entwerfen CSS-Architekturen mit klaren Cascade-Schichten, :where() für überschreibbare Bases und :is() für präzise Komponentenregeln – ohne Spezifitätskriege.

CSS-Audit

Spezifitätsprobleme, redundante Selektorlisten und Cascade-Konflikte analysieren

Selektor-Refactoring

Lange Kommalisten durch :is() und :where() ersetzen und Layer-Architektur aufbauen

Hyvä-Integration

Tailwind und Custom CSS in Magento-Themes konfliktfrei strukturieren

10. Zusammenfassung

CSS :is() und CSS :where() sind zwei der produktivitätssteigernden Pseudo-Klassen-Funktionen aus CSS Selectors Level 4. CSS :is() komprimiert Selektorlisten mit der Spezifität des spezifischsten Arguments – ideal für Komponentenstile, bei denen der Kontext Spezifität tragen soll. CSS :where() macht dasselbe mit Spezifität null – ideal für Reset-Stylesheets, Base-Layers und alle Stile, die in der Cascade immer überschreibbar sein sollen.

Das Fehlertoleranzverhalten beider Funktionen gegenüber ungültigen Selektoren in der Argumentliste macht sie sicherer als klassische Kommalisten bei der Arbeit mit Vendor-Prefixes oder zukunftsorientierten Selektoren. In Kombination mit :not(), :has() und nativer CSS-Verschachtelung entstehen Selektoren, die strukturelle Beziehungen im Dokument präzise ausdrücken, ohne HTML-Klassen zu missbrauchen. Die Grundregel für den Einsatz: CSS :where() für alles, was eine Basis darstellt – CSS :is() für alles, was gezielt überschreiben oder spezifisch sein soll.

CSS :is() und :where() — Das Wichtigste auf einen Blick

:is() Spezifität

Übernimmt die Spezifität des spezifischsten Arguments. :is(#id, .class) hat ID-Spezifität – auch wenn das Element nur durch .class gematcht wird.

:where() Spezifität

Immer null. Ideal für Reset-Stylesheets und Base-Layer: jede Klassenselektor-Regel überschreibt :where()-Styles ohne Spezifitätsprobleme.

Fehlertoleranz

Ungültige Selektoren in der :is()/:where()-Liste werden ignoriert, die Regel bleibt gültig. Klassische Kommalisten werden bei einem ungültigen Selektor vollständig verworfen.

:not() Kombination

:is(h1,h2,h3):not(.no-style) fasst Ausschlüsse kompakt zusammen. :not(:is(...)) schließt eine ganze Gruppe aus – ein Pattern, das zuvor sehr verbose war.

11. FAQ: CSS :is() und :where()

1Unterschied :is() und :where()?
:is() übernimmt Spezifität des spezifischsten Arguments. :where() hat immer Spezifität null. Matchen identisch – nur Spezifität unterscheidet sich.
2Warum :where() für Resets?
Spezifität null – jede Klassenregel überschreibt ohne !important oder hohe Spezifität. Verhindert Spezifitätskriege bei Framework-Konsumenten.
3Was bedeutet fehlertolerante Selektorliste?
Ungültige Selektoren in :is()/:where() werden ignoriert, die Regel bleibt gültig. In Kommalisten macht ein ungültiger Selektor die ganze Regel ungültig.
4:is() mit :not() kombinieren?
Ja. :is(h1,h2,h3):not(.no-style) oder :not(:is(h1,h2,h3)). Kompakte Ausschlussregeln für Gruppen von Elementen oder Klassen.
5:matches() dasselbe wie :is()?
Ja – früherer Name in der Spezifikation und in Safari 9–13. Heute immer :is() verwenden.
6:is() mit Cascade Layers?
@layer base mit :where() für Grundstile, @layer components mit :is() für Komponenten. Layers haben Vorrang vor Spezifität – innerhalb eines Layers zählt sie normal.
7Kann :is() Pseudo-Elemente enthalten?
Nein. ::before, ::after etc. sind keine gültigen Argumente. Nur Pseudo-Klassen und einfache/komplexe Selektoren sind erlaubt.
8Browser-Support 2026?
:is() und :where() sind Baseline-Features. Chrome 88+, Firefox 78+, Safari 14+. Ohne Fallback verwendbar.
9ID in :is() mischen?
Gibt der gesamten Regel ID-Spezifität (1,0,0) – auch wenn das Element durch eine Klasse gematcht wird. IDs in :is()-Argumenten vermeiden.
10:is() in nativem CSS Nesting?
.card { & :is(h2, h3) { color: purple; } } – äquivalent zu .card :is(h2, h3). Verschachtelung und :is() ergänzen sich optimal.