CSS-Selektoren lesen & einordnen bei :has(), @if, :is() und :where()

Ich tue mir bei den neuen Selektoren etwas schwer, daher hab ich mir hier etwas zusammengestellt, das mir hilft.

Grundregel zum Lesen von CSS-Selektoren

1) Bestimme zuerst das Ziel ganz rechts.
Das ist das Element, auf das der Stil am Ende angewendet wird.

2) Arbeite dich dann nach links.
Alles links vom Ziel beschreibt Bedingungen, unter denen dieser Stil gilt
(Eltern, Umgebung, Reihenfolge, Zustand, Attribute …).

3) Übersetze Kombinatoren in kurze Sätze:

  • A B → „B irgendwo innerhalb von A“
  • A > B → „B direktes Kind von A“
  • A + B → „B direkt danach
  • A ~ B → „B irgendwo danach (gleiches Eltern-Element)“

4) Pseudoklassen immer am aktuellen Element lesen.

  • :hover, :checked, :is(), :where()
    → beschreiben das Element selbst
  • :has()
    → beschreibt den Inhalt / die Umgebung dieses Elements

Mini-Formel zum Übersetzen

„Wähle [rechts] …, aber nur wenn [links] …“

:has() – Bedingung über Inhalt / Umgebung

body:has(#sidebar-toggle:checked) #sidebar {
  margin-inline-start: 0;
}

Lesart:

„Wähle #sidebar, aber nur wenn es in einem body liegt,
der ein gechecktes #sidebar-toggle enthält.“

Wichtig:

  • :has() prüft Nachfahren
  • das linke Element ist das Subjekt
  • einziges CSS-Werkzeug, das „Elternlogik“ ermöglicht

Typischer Einsatz:
Layout-States, Formular-Abhängigkeiten, UI-Zustände ohne JS

@if selector() – globaler Zustands-Schalter

@if selector(body:has(#sidebar-toggle:checked)) {
  #sidebar {
    margin-inline-start: 0;
  }
}

Lesart:

„Wenn es irgendwo im Dokument einen body gibt,
der eine gecheckte Sidebar-Checkbox enthält,
dann aktiviere diesen CSS-Block.“

Wichtig:

  • selektiert keine Elemente
  • prüft nur, ob ein Selektor irgendwo matcht
  • wirkt global, nicht strukturell

Typischer Einsatz:
Globale UI-Zustände (Modal offen, Navigation aktiv, Fokus-Lock)

:is() – ODER-Gruppe am selben Element

button:is(.primary, .danger) {
  font-weight: bold;
}

Lesart:

„Wähle button, wenn es die Klasse .primary oder .danger hat.“

Wichtig:

  • beschreibt das Element selbst
  • keine Nachfahren-Prüfung
  • Spezifität = höchste Spezifität in der Liste

Typischer Einsatz:
Selektoren zusammenfassen, Lesbarkeit erhöhen

Warum das Checkbox-Beispiel nicht geht

body:is(#sidebar-toggle:checked) #sidebar {
  margin-inline-start: 0;
}

Lesart:

„Wähle #sidebar, aber nur wenn body selbst
ein #sidebar-toggle:checked ist.“

Unmöglich, denn:

  • body ist kein input
  • :is() prüft nur das Element selbst
  • keine Nachfahren-Logik

:where() – ODER-Gruppe ohne Spezifität

:where(h1, h2, h3) {
  margin-block: 0.5em;
}

Lesart:

„Wähle h1, h2 oder h3, aber ohne Einfluss auf die Spezifität.“

Wichtig:

  • gleiche Logik wie :is()
  • Spezifität immer 0
  • ideal für Defaults und Baselines

Typischer Einsatz:
Design-Systeme, Reset-CSS, Grundlayout

Jetzt der entscheidende Punkt: Spezifität

Ohne :is() / :where()

button.primary { color: red; }

Spezifität: 0-1-1

Mit :is()

button:is(.primary, .danger) { color: red; }

Spezifität: 0-1-1
:is() übernimmt die höchste Spezifität aus der Liste

Für den Browser ist das so, als hättest du button.primary direkt geschrieben.

Mit :where()

button:where(.primary, .danger) { color: red; }

Spezifität: 0-0-1
→ die Klassen zählen nicht

:where() ist immer Spezifität 0, egal was drinsteht.

Häufiger Denkfehler (entscheidend!)

:is() und :where() können nicht sagen:

„wenn dieses Element etwas enthält“

✔️ Das kann nur :has()

Entscheidungs-Faustregeln

FragestellungRichtiger Mechanismus
Enthält dieses Element etwas Bestimmtes?:has()
Existiert ein Zustand irgendwo im DOM?@if selector()
Element ist A oder B?:is()
A oder B, aber leicht überschreibbar?:where()

Merksatz

:is() und :where() beschreiben, was ein Element ist.
:has() beschreibt, was ein Element enthält.
@if selector() beschreibt, ob ein Zustand existiert.

Damit lassen sich moderne CSS-Selektoren korrekt lesen, vergleichen und gezielt einsetzen.



Als erster einen Kommentar schreiben.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert