TL;DR: CSS :has() ist der lang ersehnte Parent Selector – du kannst jetzt endlich Eltern-Elemente basierend auf ihren Kindern stylen. Kein JavaScript mehr nötig, kein Workaround, einfach pures CSS. Und ja, es funktioniert in allen modernen Browsern.

🤔 Warum gab es nie einen Parent Selector?

Wenn du schon länger CSS schreibst, kennst du das Problem. Du willst ein Element stylen, aber die Bedingung hängt von einem Kind-Element ab. Ein Formular rot umranden, wenn ein Input ungültig ist? Ein Card-Layout anpassen, wenn ein Bild vorhanden ist? Klassisches Szenario – und klassisch unmöglich mit CSS.

Der Grund war simpel: Performance. Browser rendern CSS von rechts nach links. Ein Parent Selector hätte bedeutet, dass der Browser bei jedem Element den gesamten DOM-Baum nach oben traversieren müsste. Das war lange ein No-Go.

Aber die Browser-Engines sind besser geworden. Viel besser. Und so wurde :has() geboren.

🚀 Was ist :has() und wie funktioniert es?

Mit :has() kannst du ein Element auswählen, das ein bestimmtes Kind-Element enthält. Du schreibst quasi: "Wähle mir das Element, das dieses Kind hat."

/* Wähle jeden div, der ein p-Element enthält */
div:has(p) {
  border: 2px solid blue;
}

/* Wähle jeden article, der ein img enthält */
article:has(img) {
  grid-template-columns: 1fr 1fr;
}

Das Geniale: :has() ist nicht nur ein Parent Selector. Es ist ein relativer Selektor. Du kannst jede beliebige Selektor-Logik darin verwenden.

/* Wähle ein label, dessen nächstes Geschwister-Element ein :checked Input ist */
label:has(+ input:checked) {
  font-weight: bold;
  color: green;
}

💻 Praktische Beispiele

Formular-Validierung stylen

Statt JavaScript zu nutzen, um Klassen zu togglen, kannst du jetzt direkt mit CSS auf den Zustand deiner Inputs reagieren.

/* Fieldset rot umranden, wenn ein ungültiger Input drin ist */
fieldset:has(input:invalid) {
  border-color: red;
  background: #fff0f0;
}

/* Fieldset grün, wenn alle Inputs gültig sind */
fieldset:has(input:valid):not(:has(input:invalid)) {
  border-color: green;
  background: #f0fff0;
}

/* Submit-Button visuell deaktivieren */
form:has(input:invalid) button[type="submit"] {
  opacity: 0.5;
  pointer-events: none;
}

Card Layouts dynamisch anpassen

Stell dir ein Card-Component vor. Manchmal hat es ein Bild, manchmal nicht. Mit :has() passt du das Layout automatisch an.

.card:has(img) {
  display: grid;
  grid-template-columns: 200px 1fr;
}

.card:not(:has(img)) {
  padding: 2rem;
}

/* Card mit Video bekommt mehr Platz */
.card:has(video) {
  grid-column: span 2;
}
/* Nav-Item hervorheben, wenn es den aktiven Link enthält */
nav li:has(a.active) {
  background: #e0e7ff;
  border-radius: 8px;
}

/* Dropdown-Pfeil drehen, wenn Untermenü offen ist */
nav li:has(.submenu:not([hidden])) > .arrow {
  transform: rotate(180deg);
}
Pseudo Selector :nth-child() interaktiv erklärt
Lerne den mächtigen :nth-child() Selektor interaktiv kennen – mit praktischen Beispielen und Erklärungen.

⚙️ Kombinieren mit anderen Selektoren

Die wahre Power von :has() entfaltet sich in Kombination mit :not(), :is() und :where().

/* Element, das KEIN Bild enthält */
.card:not(:has(img)) {
  min-height: 200px;
}

/* Element, das entweder ein img ODER ein video enthält */
.card:has(:is(img, video)) {
  aspect-ratio: 16 / 9;
}

/* Spezifität-freie Variante mit :where() */
.card:has(:where(img, video)) {
  overflow: hidden;
}

Du kannst :has() auch verschachteln – ja, wirklich:

/* Section, die eine Card enthält, die ein Bild enthält */
section:has(.card:has(img)) {
  padding: 2rem;
}

🎨 Real-World Use Cases

Hat eine aktivierte Checkbox

/* Zeile hervorheben, wenn Checkbox gecheckt */
tr:has(input[type="checkbox"]:checked) {
  background: #e0f2fe;
}

/* Dark Mode Toggle ohne JavaScript */
body:has(#dark-mode:checked) {
  --bg: #1a1a2e;
  --text: #e0e0e0;
  background: var(--bg);
  color: var(--text);
}

Hat einen leeren Input

/* Placeholder-Styling, wenn Input leer ist */
.form-group:has(input:placeholder-shown) label {
  color: #999;
  transform: translateY(0);
}

/* Floating Label Effekt */
.form-group:has(input:not(:placeholder-shown)) label {
  transform: translateY(-1.5rem);
  font-size: 0.75rem;
  color: #3b82f6;
}

Hat ein bestimmtes Kind-Element

/* Sidebar nur anzeigen, wenn Content vorhanden */
.layout:has(.sidebar:not(:empty)) {
  grid-template-columns: 1fr 300px;
}

.layout:not(:has(.sidebar:not(:empty))) {
  grid-template-columns: 1fr;
}

/* Figcaption-Abstand nur wenn vorhanden */
figure:has(figcaption) img {
  margin-bottom: 0;
  border-radius: 8px 8px 0 0;
}

⚠️ Performance – Worauf du achten solltest

Ja, :has() ist mächtig. Aber mit großer Macht kommt große Verantwortung.

Ein paar Regeln:

  • Vermeide zu breite Selektoren. :has(div) auf dem body zwingt den Browser, den gesamten DOM zu durchsuchen.
  • Sei spezifisch. .card:has(> img) (direktes Kind) ist performanter als .card:has(img) (beliebige Tiefe).
  • Nutze den direkten Kind-Kombinator > wo möglich.
  • Teste mit großen DOMs. Was bei 50 Elementen flüssig läuft, kann bei 5000 ruckeln.
/* ❌ Zu breit – potenziell langsam */
div:has(span) { ... }

/* ✅ Spezifisch und performant */
.card:has(> .card-image) { ... }

🛡️ Browser Support

:has() wird von allen modernen Browsern unterstützt:

BrowserVersionSeit
Chrome105+August 2022
Firefox121+Dezember 2023
Safari15.4+März 2022
Edge105+August 2022

Safari war hier tatsächlich der Vorreiter – ungewöhnlich, aber willkommen. Firefox hat etwas länger gebraucht, aber seit Ende 2023 sind alle großen Browser an Bord.

Can I Use – CSS :has()
Browser support tables for modern web technologies. Check the current support for CSS :has() across all major browsers.
:has() – CSS | MDN
Die CSS-Pseudoklasse :has() repräsentiert ein Element, wenn einer der als Argument übergebenen relativen Selektoren mindestens ein Element matched.

💡 Fazit

CSS :has() ist kein Hype – es ist ein Game Changer. Jahrelang haben wir JavaScript-Workarounds gebaut, Klassen hin- und hertoggled und uns mit dem Kaskadenmodell herumgeschlagen. Das ist jetzt vorbei.

Du kannst Parent-Elemente stylen, auf Zustände von Kind-Elementen reagieren und komplexe UI-Logik direkt in CSS abbilden. Die Browser-Unterstützung ist da, die Performance ist gut (wenn du es richtig machst), und die Möglichkeiten sind endlos.

Also: Fang an, :has() zu nutzen. Dein CSS wird es dir danken.

Artikel teilen:Share article:

Mehr Artikel entdecken

htmx: Interactive Websites Without JavaScript Frameworks 🔄
Vorheriger Artikel

htmx: Interactive Websites Without JavaScript Frameworks 🔄

TL;DR: htmx makes your websites interactive without React, Angular, or Vue. A few HTML attributes replace tons of JavaScript while still delivering dynamic UIs. Here's how it works and when it makes sense. 🤔 What Is htmx, Anyway? Imagine making your website interactive without writing a single line

7 min read 25. Apr. 2026
CSS :has() – The Parent Selector Everyone’s Been Waiting For 🎯
Nächster Artikel

CSS :has() – The Parent Selector Everyone’s Been Waiting For 🎯

TL;DR: CSS :has() is the long-awaited parent selector – you can finally style parent elements based on their children. No more JavaScript hacks, no workarounds, just pure CSS. And yes, it works in all modern browsers. 🤔 Why CSS Never Had a Parent Selector If you've been writing CSS

4 min read 27. Apr. 2026
Container Queries in CSS: Das Ende von Media Queries? 📦
Ähnlicher Artikel

Container Queries in CSS: Das Ende von Media Queries? 📦

Container Queries machen Schluss mit dem Viewport-Chaos! 📦 Wie du deine Komponenten endlich wirklich responsive machst – und warum Media Queries trotzdem nicht tot sind.

4 min read 14. März 2026
Angular und TailwindCSS
Ähnlicher Artikel

Angular und TailwindCSS

Angular und TailwindCSS sind ein starkes Duo. So richtest du Tailwind in deinem Angular-Projekt ein und nutzt Utility-First CSS effektiv.

4 min read 13. März 2026
Tailwind CSS vs. Vanilla CSS – Wann lohnt sich was? ⚖️
Ähnlicher Artikel

Tailwind CSS vs. Vanilla CSS – Wann lohnt sich was? ⚖️

Tailwind CSS oder doch lieber Vanilla CSS? ⚖️ Ich zeige dir, wann sich welcher Ansatz wirklich lohnt – mit Praxisbeispielen und ehrlichen Vor- und Nachteilen!

5 min read 11. März 2026
CSS-Variablen: Flexibles Styling für deine Komponenten 🎨
Ähnlicher Artikel

CSS-Variablen: Flexibles Styling für deine Komponenten 🎨

CSS-Variablen machen dein Styling flexibler 🎯 Wie du sie nutzt, scopst und in Komponenten überschreibst, erkläre ich dir in diesem Guide! 🌈

3 min read 28. März 2025