</> HTML5Advent
ENFRESDEITPT

// css · Web Platform Advent #17

Der CSS :has() Selektor: der Eltern-Selektor, erklärt (2026)

Die relationale Pseudoklasse :has() ermöglicht es, ein Element auf Basis seines Inhalts oder des Folgenden zu gestalten - der lang ersehnte Eltern-Selektor. Wie er funktioniert, echte Beispiele, Browser-Unterstützung und die Fallstricke.

Nahaufnahme farbiger CSS-Codezeilen auf einem Computerbildschirm

Die Pseudoklasse :has() ist die Funktion, die CSS-Autoren zwei Jahrzehnte lang gefordert haben: eine Möglichkeit, ein Element auf Basis dessen zu gestalten, was darin steht oder was danach kommt. Man nennt sie meist den "Eltern-Selektor", obwohl sie tatsächlich mächtiger ist als das - sie ist ein relationaler Selektor. Sie ist inzwischen in jedem modernen Browser verfügbar, sodass du sie heute im Produktivbetrieb einsetzen kannst.

Die Grundidee

Ein normaler CSS-Selektor spricht ein Element über seinen eigenen Typ, seine Klasse oder seinen Zustand an. :has() dreht das um: Es spricht ein Element aufgrund der Elemente an, die es enthält. Du schreibst das Elternelement, dann :has(...) mit einem Selektor für das, was darin sein muss.

/* Style any .card that contains an <img> */
.card:has(img) {
  padding: 0;
}

/* Style a <figure> only when it has a caption */
figure:has(figcaption) {
  border: 1px solid #ddd;
}

Das Element, das tatsächlich gestaltet wird, ist dasjenige vor :has() - die .card und die figure, nicht das Bild oder die Bildunterschrift darin. Das ist der ganze Trick: Die Bedingung betrifft die Nachfahren, aber das Ziel ist der Vorfahre.

Es ist relational, nicht nur "Eltern"

Da du Kombinatoren innerhalb von :has() platzieren kannst, leistet es weit mehr, als nur auf Kindelemente zu blicken. Du kannst auf Geschwisterelemente reagieren, was in CSS zuvor unmöglich war.

/* A heading that is immediately followed by a paragraph */
h2:has(+ p) {
  margin-bottom: 0.25rem;
}

/* A form that contains an invalid field */
form:has(input:invalid) {
  border-left: 3px solid crimson;
}

/* A label whose related required input is empty and focused */
.field:has(input:required:placeholder-shown) .hint {
  opacity: 1;
}

Das zweite Beispiel ist genau die Art von Sache, für die man früher zu JavaScript gegriffen hätte: das Aussehen eines ganzen Formulars (oder eines beliebigen Containers) auf Basis des Zustands eines Steuerelements darin zu ändern. Mit :has() ist es eine Zeile CSS, und sie aktualisiert sich live, während der Nutzer tippt.

Nahaufnahme von HTML- und CSS-Code auf einem Bildschirm
:has() liest die Beziehung zwischen Elementen, sodass ein Container auf den Inhalt und Zustand darin reagieren kann - ganz ohne JavaScript.

Praktische Muster

  • Mengen- und Inhaltsabfragen: gestalte eine Galerie anders, wenn sie genau ein Bild statt vieler enthält - .gallery:has(img:only-child).
  • Gestaltung des vorherigen Geschwisterelements: CSS konnte mit + und ~ immer nur nach vorne blicken; :has() lässt ein früheres Element auf ein späteres reagieren, z. B. label:has(+ input:checked).
  • Layout, das sich an den Inhalt anpasst: gib einer Karte nur dann ein zweispaltiges Layout, wenn sie tatsächlich ein Bild enthält, und eine einzelne Spalte, wenn nicht.
  • Formular- und Validierungszustände: hebe ein ganzes Fieldset hervor, wenn ein Steuerelement darin ungültig ist, ganz ohne eine Zeile Skript.

Browser-Unterstützung

Die Unterstützung ist 2026 breit. :has() erschien in Chrome und Edge 105 (August 2022) und Safari 15.4, wobei Firefox in Version 121 (Dezember 2023) hinzukam. Das bedeutet, dass es nun in den aktuellen Versionen aller großen Browser verfügbar ist und für die meisten Zielgruppen sicher eingesetzt werden kann. Für ältere Browser kannst du :has()-Stile als progressive Verbesserung behandeln, da ein Browser, der den Selektor nicht versteht, die Regel einfach ignoriert.

Wissenswerte Fallstricke

  • Du kannst innerhalb von :has() keine Pseudoelemente ansprechen. Selektoren wie ::before sind als Argument nicht erlaubt.
  • :has() selbst ist innerhalb von :has() nicht erlaubt. Du kannst eine relationale Prüfung nicht in einer anderen verschachteln.
  • Halte den Geltungsbereich vernünftig. Sehr breite Selektoren wie body:has(...), die den Browser zwingen, große Teile der Seite erneut zu prüfen, können bei großen, sich häufig aktualisierenden Dokumenten Leistung kosten. In der Praxis sind auf Komponenten begrenzte Selektoren in Ordnung; die Engines haben die üblichen Fälle optimiert.
  • Das Ziel ist das Subjekt, nicht die Übereinstimmung. Wenn eine Regel nicht angewendet wird, prüfe, ob du das Element vor :has() gestaltest und nicht das darin enthaltene.

FAQ

Ist :has() wirklich der CSS-Eltern-Selektor? Im Grunde ja, und mehr. Es wählt einen Vorfahren auf Basis seiner Nachfahren aus, was der klassische Anwendungsfall des "Eltern-Selektors" ist, aber da es Kombinatoren akzeptiert, kann es auch auf Basis folgender Geschwisterelemente auswählen, sodass es besser als relationaler Selektor beschrieben wird.

Kann ich :has() 2026 im Produktivbetrieb nutzen? Für die meisten Websites ja - es wird in den aktuellen Versionen aller großen Browser unterstützt. Nutze es als progressive Verbesserung, falls du sehr alte Browser unterstützen musst.

Beeinträchtigt :has() die Leistung? Selten, wenn du die Selektoren eng begrenzt hältst. Extrem breite, dokumentweite :has()-Prüfungen auf großen, sich ständig ändernden Seiten können Kosten verursachen, aber die Nutzung auf Komponentenebene ist in Ordnung.

Für weiteres modernes CSS siehe unsere Leitfäden zu nativem CSS-Nesting und Container-Abfragen.