Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.

View in English Always switch to English

:has()

Baseline 2023
Newly available

Since ⁨December 2023⁩, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

Die funktionale :has() CSS Pseudoklasse repräsentiert ein Element, wenn eines der relativen Selektoren, das als Argument übergeben wird, mindestens ein Element trifft, wenn es gegen dieses Element verankert ist. Diese Pseudoklasse bietet eine Möglichkeit, ein Elternelement oder ein vorheriges Geschwisterelement in Bezug auf ein Referenzelement zu selektieren, indem eine relative Selektorliste als Argument genommen wird.

css
/* Selects an h1 heading with a
paragraph element that immediately follows
the h1 and applies the style to h1 */
h1:has(+ p) {
  margin-bottom: 0;
}

Die :has() Pseudoklasse übernimmt die Spezifität des spezifischsten Selektors in ihren Argumenten auf die gleiche Weise wie :is() und :not().

Syntax

css
:has(<relative-selector-list>) {
  /* ... */
}

Wenn die :has() Pseudoklasse in einem Browser nicht unterstützt wird, schlägt der gesamte Selektorblock fehl, es sei denn, :has() befindet sich in einer toleranten Selektorliste, wie z.B. in :is() und :where().

Die :has() Pseudoklasse kann nicht innerhalb einer anderen :has() geschachtelt werden.

Pseudo-Elemente sind auch keine gültigen Selektoren innerhalb von :has() und dürfen nicht als Anker für :has() verwendet werden. Dies liegt daran, dass viele Pseudo-Elemente bedingt basierend auf dem Styling ihrer Vorfahren existieren und die Abfrage dieser durch :has() zu zyklischen Abfragen führen kann.

Beispiele

Auswahl eines Elternelements

Sie suchen möglicherweise nach einem "Eltern-Kombinator", der es Ihnen ermöglicht, im DOM-Baum nach oben zu gehen und das übergeordnete Element eines bestimmten Elements zu selektieren. Die :has() Pseudoklasse tut dies, indem sie parent:has(child) (für ein beliebiges übergeordnetes Element) oder parent:has(> child) (für direktes übergeordnetes Element) verwendet. Dieses Beispiel zeigt, wie ein <section>-Element gestylt wird, wenn es ein Kind mit der Klasse featured enthält.

html
<section>
  <article class="featured">Featured content</article>
  <article>Regular content</article>
</section>
<section>
  <article>Regular content</article>
</section>
css
section:has(.featured) {
  border: 2px solid blue;
}

Ergebnis

Mit dem Geschwisterknoten-Kombinator

Die :has() Stil-Deklaration im folgenden Beispiel passt den Abstand nach <h1> Überschriften an, wenn sie unmittelbar von einer <h2> Überschrift gefolgt werden.

HTML

html
<section>
  <article>
    <h1>Morning Times</h1>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
      tempor incididunt ut labore et dolore magna aliqua.
    </p>
  </article>
  <article>
    <h1>Morning Times</h1>
    <h2>Delivering you news every morning</h2>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
      tempor incididunt ut labore et dolore magna aliqua.
    </p>
  </article>
</section>

CSS

css
h1,
h2 {
  margin: 0 0 1rem 0;
}

h1:has(+ h2) {
  margin: 0 0 0.25rem 0;
}

Ergebnis

Dieses Beispiel zeigt zwei ähnliche Texte nebeneinander zum Vergleich – den linken mit einer H1-Überschrift gefolgt von einem Absatz und den rechten mit einer H1-Überschrift gefolgt von einer H2-Überschrift und dann einem Absatz. Im rechten Beispiel hilft :has(), das H1-Element auszuwählen, das unmittelbar von einem H2-Element gefolgt wird (angezeigt durch den nächsten Geschwisterkombiator +), und die CSS-Regel reduziert den Abstand nach einem solchen H1-Element. Ohne die :has() Pseudoklasse können Sie keine CSS-Selektoren verwenden, um ein vorangehendes Geschwisterelement eines anderen Typs oder ein übergeordnetes Element zu selektieren.

Mit der :is() Pseudo-Klasse

Dieses Beispiel baut auf dem vorherigen Beispiel auf, um zu zeigen, wie mehrere Elemente mit :has() ausgewählt werden.

HTML

html
<section>
  <article>
    <h1>Morning Times</h1>
    <h2>Delivering you news every morning</h2>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
      tempor incididunt ut labore et dolore magna aliqua.
    </p>
  </article>
  <article>
    <h1>Morning Times</h1>
    <h2>Delivering you news every morning</h2>
    <h3>8:00 am</h3>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
      tempor incididunt ut labore et dolore magna aliqua.
    </p>
  </article>
</section>

CSS

css
h1,
h2,
h3 {
  margin: 0 0 1rem 0;
}

:is(h1, h2, h3):has(+ :is(h2, h3, h4)) {
  margin: 0 0 0.25rem 0;
}

Ergebnis

Hier wird die erste :is() Pseudoklasse verwendet, um eines der Überschriftselemente in der Liste auszuwählen. Die zweite :is() Pseudoklasse wird verwendet, um eine Liste von Geschwisterselektoren als Argument an :has() zu übergeben. Die :has() Pseudoklasse hilft, jedes H1, H2 oder H3 Element auszuwählen, das unmittelbar von (angezeigt durch +) einem H2, H3 oder H4-Element gefolgt wird und die CSS-Regel reduziert den Abstand nach solchen H1, H2 oder H3 Elementen.

Dieser Selektor könnte auch so geschrieben werden:

css
:is(h1, h2, h3):has(+ h2, + h3, + h4) {
  margin: 0 0 0.25rem 0;
}

Logische Operationen

Der :has() relationale Selektor kann verwendet werden, um zu überprüfen, ob eines der mehreren Merkmale wahr ist oder ob alle Merkmale wahr sind.

Durch die Verwendung von kommagetrennten Werten innerhalb des relationalen :has() Selektors überprüfen Sie, ob eines der Parameter existiert. x:has(a, b) wird x stylen, wenn Nachfahre a ODER b existiert.

Durch das Aneinanderreihen mehrerer relationaler :has() Selektoren prüfen Sie, ob alle Parameter existieren. x:has(a):has(b) wird x stylen, wenn Nachfahre a UND b existieren.

css
body:has(video, audio) {
  /* styles to apply if the content contains audio OR video */
}
body:has(video):has(audio) {
  /* styles to apply if the content contains both audio AND video */
}

Analogie zwischen :has() und regulären Ausdrücken

Interessanterweise können wir einige CSS :has() Konstrukte mit der Lookahead Assertion in regulären Ausdrücken in Verbindung bringen, da beide es ermöglichen, Elemente (oder Zeichenfolgen in regulären Ausdrücken) basierend auf einer Bedingung auszuwählen, ohne tatsächlich das der Bedingung entsprechende Element (oder die Zeichenfolge) selbst auszuwählen.

Positiver Lookahead (?=pattern)

Im regulären Ausdruck abc(?=xyz) wird die Zeichenfolge abc nur dann gematcht, wenn sie unmittelbar von der Zeichenfolge xyz gefolgt wird. Da es sich um eine Lookahead-Operation handelt, wird xyz nicht in den Match einbezogen.

Das analoge Konstrukt in CSS wäre .abc:has(+ .xyz): es selektiert das Element .abc, nur wenn es ein nächstes Geschwister .xyz gibt. Der Teil :has(+ .xyz) wirkt wie eine Lookahead-Operation, weil das Element .abc ausgewählt wird und nicht das Element .xyz.

Negativer Lookahead (?!pattern)

Ähnlich verhält es sich beim negativen Lookahead. Im regulären Ausdruck abc(?!xyz) wird die Zeichenfolge abc nur dann gematcht, wenn sie nicht von xyz gefolgt wird. Das analoge CSS-Konstrukt .abc:has(+ :not(.xyz)) selektiert das Element .abc nicht, wenn das nächste Element .xyz ist.

Leistungsüberlegungen

Bestimmte Verwendungen der :has() Pseudoklasse können die Leistung der Seite erheblich beeinträchtigen, insbesondere während dynamischer Aktualisierungen (DOM-Mutationen). Browser-Engines müssen :has() Selektoren neu bewerten, wenn sich das DOM ändert, und komplexe oder schlecht eingeschränkte Selektoren können zu teuren Berechnungen führen.

Vermeiden Sie breite Anker

Der Ankerselektor (das A in A:has(B)) sollte kein Element sein, das zu viele Kinder hat, wie body, :root oder *. Die Verankerung von :has() an sehr allgemeinen Selektoren kann die Leistung verschlechtern, da jede DOM-Änderung innerhalb des gesamten Teilbaums eines breit ausgewählten Elements den Browser erfordert, die :has() Bedingung erneut zu überprüfen.

css
/* Avoid anchoring :has() to broad elements */
body:has(.sidebar) {
  /* styles */
}
:root:has(.content) {
  /* styles */
}
*:has(.item) {
  /* styles */
}

Stattdessen sollten Sie :has() an spezifische Elemente wie .container oder .gallery verankern, um den Umfang zu reduzieren und die Leistung zu verbessern.

css
/* Use specific containers to limit scope */
.container:has(.sidebar-expanded) {
  /* styles */
}
.content-wrapper:has(> article[data-priority="high"]) {
  /* styles */
}
.gallery:has(> img[data-loaded="false"]) {
  /* styles */
}

Minimieren Sie die Traversal von Teilbäumen

Der innere Selektor (das B in A:has(B)) sollte Kombinatoren wie > oder + verwenden, um die Traversierung zu begrenzen. Wenn der Selektor innerhalb von :has() nicht eng eingeschränkt ist, muss der Browser möglicherweise den gesamten Teilbaum des Ankerelements bei jeder DOM-Änderung durchqueren, um zu überprüfen, ob die Bedingung noch zutrifft.

In diesem Beispiel erfordert jede Änderung innerhalb von .ancestor, dass alle Nachkommen auf .foo überprüft werden:

css
/* May trigger full subtree traversal */
.ancestor:has(.foo) {
  /* styles */
}

Die Verwendung von Kinder- oder Geschwisterkombiatoren begrenzt den Umfang des inneren Selektors und reduziert die Leistungskosten von DOM-Mutationen. In diesem Beispiel muss der Browser nur direkte Kinder oder die Nachkommen eines bestimmten Geschwisters überprüfen:

css
/* More constrained - limits traversal */
.ancestor:has(> .foo) {
  /* direct child */
}
.ancestor:has(+ .sibling .foo) {
  /* descendant of adjacent sibling */
}

Bestimmte innere Selektoren können den Browser zwingen, bei jeder DOM-Änderung die Ahnenkette nach potenziellen Ankern zu durchlaufen, die möglicherweise aktualisiert werden müssen. Dies geschieht, wenn die Struktur impliziert, dass die Ahnen des mutierten Elements überprüft werden müssen.

In diesem Beispiel erfordert jede DOM-Änderung, dass geprüft wird, ob das geänderte Element ein beliebiges Element (*) ist, das ein direktes Kind von .foo ist, und ob sein Elternteil (oder weitere Vorfahren) .ancestor ist.

css
/* Might trigger ancestor traversal */
.ancestor:has(.foo > *) {
  /* styles */
}

Das Einschränken des inneren Selektors mit spezifischen Klassen oder direkten Kinder-Kombinatoren (z. B. .specific-child im nächsten Snippet) reduziert teure Ahnen-Traversalen, indem die Überprüfung des Browsers auf ein klar definiertes Element beschränkt wird, was die Leistung verbessert.

css
/* Constrain the inner selector to avoid ancestor traversals */
.ancestor:has(.foo > .specific-child) {
  /* styles */
}

Hinweis: Diese Leistungseigenschaften können sich verbessern, wenn Browser die :has() Implementierungen optimieren, aber die grundlegenden Einschränkungen bleiben bestehen: :has() muss einen ganzen Teilbaum durchqueren, daher sollten Sie die Größe des Teilbaums minimieren. In einem Selektor wie A:has(B), stellen Sie sicher, dass Ihr A nicht zu viele Kinder hat und dass Ihr B streng eingeschränkt ist, um unnötige Traversalen zu vermeiden.

Spezifikationen

Specification
Selectors Level 4
# relational

Browser-Kompatibilität

Siehe auch