Ein Leitfaden für neu unterstützte, moderne CSS-Pseudo-Klassen-Selektoren

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Der CSS Working Group Editor's Draft for Selectors Level 4 enthält mehrere Pseudo-Klassen-Selektoren, die bereits Vorschlagskandidaten in den meisten modernen Browsern haben. Dieser Leitfaden behandelt diejenigen, die derzeit die beste Unterstützung haben, zusammen mit Beispielen, um zu zeigen, wie Sie sie heute verwenden können!

Pseudo-Klassen-Selektoren beginnen mit dem Doppelpunktzeichen „ : “ und stimmen basierend auf einem Status des aktuellen Elements überein. Der Status kann relativ zum Dokumentbaum sein oder als Reaktion auf eine Statusänderung wie :hover oder :checked .

:any-link

Obwohl diese Pseudoklasse in Selectors Level 4 definiert ist, wird sie seit geraumer Zeit browserübergreifend unterstützt. Die any-link -Pseudoklasse stimmt mit einem Anker-Hyperlink überein, solange er ein href hat. Es wird auf eine Weise übereinstimmen, die der gleichzeitigen Übereinstimmung von :link und :visited entspricht. Im Wesentlichen kann dies Ihre Stile um einen Selektor reduzieren, wenn Sie grundlegende Eigenschaften wie color hinzufügen, die Sie auf alle Links anwenden möchten, unabhängig von ihrem besuchten Status.

 :any-link { color: blue; text-underline-offset: 0.05em; }

Ein wichtiger Hinweis zur Spezifität ist, dass :any-link gegen a als Selektor gewinnt, selbst wenn a in der Kaskade niedriger platziert wird, da es die Spezifität einer Klasse hat. Im folgenden Beispiel sind die Links violett:

 :any-link { color: purple; } a { color: red; }

Wenn Sie also :any-link einführen, beachten Sie, dass Sie es in Instanzen von a als Selektor einschließen müssen, wenn sie in direktem Wettbewerb um die Spezifität stehen.

:focus-visible

Ich wette, dass einer der häufigsten Verstöße gegen die Barrierefreiheit im Web darin besteht, den outline interaktiver Elemente wie Links, Schaltflächen und Formulareingaben für ihren :focus -Status zu entfernen. Einer der Hauptzwecke dieser outline besteht darin, als visueller Indikator für Benutzer zu dienen, die hauptsächlich Tastaturen zum Navigieren verwenden. Ein sichtbarer Fokusstatus ist als Wegfindungstool von entscheidender Bedeutung, wenn diese Benutzer mit der Tabulatortaste über eine Benutzeroberfläche navigieren, und um dabei zu helfen, das, was ein interaktives Element ist, zu verstärken. Insbesondere der sichtbare Fokus wird im WCAG-Erfolgskriterium 2.4.11 abgedeckt: Fokusaussehen (Minimum).

Die :focus-visible soll einen Fokusring nur anzeigen, wenn der Benutzeragent über Heuristik feststellt, dass er sichtbar sein soll. Anders ausgedrückt: Browser bestimmen, wann :focus-visible angewendet werden soll, basierend auf Dingen wie der Eingabemethode, dem Elementtyp und dem Kontext der Interaktion. Zu Testzwecken über einen Desktop-Computer mit Tastatur- und Mauseingabe sollten Sie :focus-visible Stile angehängt sehen, wenn Sie mit der Tabulatortaste in ein interaktives Element wechseln, aber nicht, wenn Sie darauf klicken, mit Ausnahme von Texteingaben und Textbereichen, die :focus-visible sollten. :focus-visible für alle Fokuseingabetypen.

Hinweis : Weitere Einzelheiten finden Sie im Arbeitsentwurf der :focus-visible Spezifikation.

Die neuesten Versionen von Firefox- und Chromium-Browsern scheinen jetzt :focus-visible bei Formulareingaben gemäß der Spezifikation zu handhaben, die besagt, dass die UA :focus -Stile entfernen sollte, wenn :focus-visible übereinstimmt. Safari unterstützt :focus-visible noch nicht, daher müssen wir sicherstellen, dass ein :focus -Stil als Fallback enthalten ist, um zu vermeiden, dass die outline für die Barrierefreiheit entfernt wird.

Mehr nach dem Sprung! Lesen Sie unten weiter ↓

Sehen wir uns bei einer Schaltfläche und einer Texteingabe mit den folgenden Stilen an, was passiert:

 input:focus, button:focus { outline: 2px solid blue; outline-offset: 0.25em; } input:focus-visible { outline: 2px solid transparent; border-color: blue; } button:focus:not(:focus-visible) { outline: none; } button:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 2px #fff, 0 0 0 4px blue; }

Chrom und Firefox

  • input
    Korrektes Entfernen von :focus -Stilen, wenn Elemente per Mauseingabe fokussiert werden, zugunsten von :focus-visible , was dazu führt, dass die border-color und der outline bei Tastatureingaben ausgeblendet wird
  • button
    Verwendet nicht nur :focus-visible ohne die zusätzliche Regel für button:focus:not(:focus-visible) , die den Umriss von :focus entfernt, sondern ermöglicht die Sichtbarkeit des box-shadow nur bei Tastatureingaben

Safari

  • input
    Verwendet weiterhin nur die :focus -Stile
  • button
    Dies scheint jetzt teilweise die Absicht von :focus-visible auf der Schaltfläche zu respektieren, indem die :focus -Stile beim Klicken ausgeblendet werden, die :focus -Stile jedoch weiterhin bei der Tastaturinteraktion angezeigt werden

Daher wäre die Empfehlung vorerst, weiterhin :focus -Stile einzubeziehen und dann schrittweise bis zur Verwendung von :focus-visible zu erweitern, was der Democode zulässt. Hier ist ein CodePen, mit dem Sie weiter testen können:

Siehe Pen [Testing application of :focus-visible](https://codepen.io/smashingmag/pen/MWJZbew) von Stephanie Eckles.

Siehe die Pen-Testing-Anwendung von :focus-visible von Stephanie Eckles.

:focus-within

Die :focus-within wird von allen modernen Browsern unterstützt und verhält sich fast wie ein übergeordneter Selektor, jedoch nur für eine ganz bestimmte Bedingung. Wenn sie an ein enthaltendes Element angehängt sind und ein untergeordnetes Element mit :focus übereinstimmt, können Stile dem enthaltenden Element und/oder anderen Elementen innerhalb des Containers hinzugefügt werden.

Eine praktische Verbesserung, um dieses Verhalten zu verwenden, ist das Gestalten einer Formularbeschriftung, wenn die zugehörige Eingabe den Fokus hat. Damit dies funktioniert, packen wir das Label und die Eingabe in einen Container und hängen dann :focus-within an diesen Container an und wählen das Label aus:

 .form-group:focus-within label { color: blue; }

Dies führt dazu, dass das Etikett blau wird, wenn die Eingabe den Fokus hat.

Diese CodePen-Demo beinhaltet auch das Hinzufügen einer Gliederung direkt zum .form-group Container:

Siehe Pen [Testing application of :focus-within](https://codepen.io/smashingmag/pen/xxgmREq) von Stephanie Eckles.

Siehe die Pen-Testing-Anwendung von :focus-within von Stephanie Eckles.

:is()

:is() , auch bekannt als die Pseudoklasse „trifft auf alle zu“, kann eine Liste von Selektoren annehmen, mit denen versucht wird, eine Übereinstimmung zu finden. Anstatt beispielsweise Überschriftenstile einzeln aufzulisten, können Sie sie unter dem Selektor von :is(h1, h2, h3) gruppieren.

Einige einzigartige Verhaltensweisen der :is() Auswahlliste:

  • Wenn ein aufgelisteter Selektor ungültig ist, stimmt die Regel weiterhin mit den gültigen Selektoren überein. Bei :is(-ua-invalid, article, p) die Regel mit article und p überein.
  • Die berechnete Spezifität entspricht der des übergebenen Selektors mit der höchsten Spezifität. Zum Beispiel hat :is(#id, p) die Spezifität der #id – 1.0.0 – während :is(p, a) eine Spezifität von 0.0.1 hat.

Das erste Verhalten, ungültige Selektoren zu ignorieren, ist ein entscheidender Vorteil. Wenn andere Selektoren in einer Gruppe verwendet werden, in der ein Selektor ungültig ist, verwirft der Browser die gesamte Regel. Dies kommt in einigen Fällen ins Spiel, in denen Herstellerpräfixe immer noch erforderlich sind und das Gruppieren von Selektoren mit und ohne Präfix dazu führt, dass die Regel bei allen Browsern fehlschlägt. Mit :is() können Sie diese Stile sicher gruppieren und sie werden angewendet, wenn sie übereinstimmen, und ignoriert, wenn dies nicht der Fall ist.

Für mich ist das Gruppieren von Überschriftenstilen, wie zuvor erwähnt, mit diesem Selektor bereits ein großer Gewinn. Es ist auch die Art von Regel, die ich gerne ohne Fallback verwenden würde, wenn ich unkritische Stile anwende, wie zum Beispiel:

 :is(h1, h2, h3) { line-height: 1.2; } :is(h2, h3):not(:first-child) { margin-top: 2em; }

In diesem Beispiel (das aus den Dokumentstilen in meinem Projekt SmolCSS stammt) ist die größere line-height , die von den Basisstilen geerbt wird, oder das Fehlen margin-top kein wirkliches Problem für nicht unterstützende Browser. Es ist einfach alles andere als ideal. Wofür Sie :is() noch nicht verwenden möchten, sind kritische Layoutstile wie Grid oder Flex, die Ihre Benutzeroberfläche erheblich steuern.

Wenn Sie mit einem anderen Selektor verkettet sind, können Sie außerdem testen, ob der Basisselektor mit einem untergeordneten Selektor innerhalb von :is() übereinstimmt. Beispielsweise wählt die folgende Regel nur Absätze aus, die direkte Nachkommen von Artikeln sind. Der Universalselektor wird als Referenz zum p -Basisselektor verwendet.

 p:is(article > *)

Für die beste aktuelle Unterstützung sollten Sie, wenn Sie damit beginnen möchten, auch Stile verdoppeln, indem Sie doppelte Regeln mit :-webkit-any() und :matches() einfügen. Denken Sie daran, diese individuellen Regeln zu erstellen, oder sogar der unterstützende Browser wird sie verwerfen! Mit anderen Worten, schließen Sie Folgendes ein:

 :matches(h1, h2, h3) { } :-webkit-any(h1, h2, h3) { } :is(h1, h2, h3) { }

Erwähnenswert an dieser Stelle ist, dass es zusammen mit den neueren Selektoren selbst eine aktualisierte Variante von @supports gibt, @supports selector . Dies ist auch als @supports not selector verfügbar.

Hinweis : Derzeit (von den modernen Browsern) unterstützt nur Safari diese At-Regel nicht.

Sie könnten mit etwas wie dem Folgenden nach der Unterstützung von :is() suchen, aber Sie würden tatsächlich die Unterstützung von Safari verlieren, da Safari :is() :is() unterstützt, aber @supports selector nicht unterstützt.

 @supports selector(:is(h1)) { :is(h1, h2, h3) { line-height: 1.1; } }

:where()

Die Pseudo-Klasse :where() ist fast identisch mit :is() mit Ausnahme eines entscheidenden Unterschieds: Sie hat immer eine Null-Spezifität. Dies hat unglaubliche Auswirkungen auf Leute, die Frameworks, Themes und Designsysteme erstellen . Mit :where() kann ein Autor Standardwerte festlegen und nachgeschaltete Entwickler können Überschreibungen oder Erweiterungen einschließen, ohne dass die Spezifität kollidiert.

Betrachten Sie den folgenden Satz von img -Stilen. Bei Verwendung von :where() bleibt die Spezifität auch bei einem Selektor mit höherer Spezifität null. Welche Randfarbe wird das Bild im folgenden Beispiel Ihrer Meinung nach haben?

 :where(article img:not(:first-child)) { border: 5px solid red; } :where(article) img { border: 5px solid green; } img { border: 5px solid orange; }

Die erste Regel hat keine Spezifität, da sie vollständig in :where() enthalten ist. Also direkt gegen die zweite Regel gewinnt die zweite Regel. Die Einführung des Nur-Element-Selektors img als letzte Regel wird aufgrund der Kaskade gewinnen. Dies liegt daran, dass es mit der gleichen Spezifität wie die :where(article) img Regel berechnet wird, da der :where() Teil die Spezifität nicht erhöht.

Die Verwendung von :where() neben Fallbacks ist aufgrund der Null-Spezifitätsfunktion etwas schwieriger, da diese Funktion wahrscheinlich der Grund dafür ist, dass Sie sie über :is() verwenden möchten . Und wenn Sie Fallback-Regeln hinzufügen, werden diese wahrscheinlich :where() aufgrund seiner Natur schlagen. Und es hat insgesamt eine bessere Unterstützung als der @supports selector , so dass der Versuch, diesen zum Erstellen eines Fallbacks zu verwenden, wahrscheinlich keinen großen (wenn überhaupt) Gewinn bringt. Seien Sie sich grundsätzlich der Unfähigkeit bewusst, Fallbacks für :where() korrekt zu erstellen, und überprüfen Sie Ihre eigenen Daten sorgfältig, um festzustellen, ob es sicher ist, mit der Verwendung für Ihr einzigartiges Publikum zu beginnen.

Sie können :where() mit dem folgenden CodePen weiter testen, der die img -Selektoren von oben verwendet:

Siehe Pen [Testing `:where()` specificity](https://codepen.io/smashingmag/pen/jOyXVMg) von Stephanie Eckles.

Siehe Pen Testing :where() Spezifität von Stephanie Eckles.

Verbessert :not()

Der Basisselektor :not() wird seit Internet Explorer 9 unterstützt. Aber Selectors Level 4 verbessert :not() , indem es ihm erlaubt, eine Selektorliste zu nehmen, genau wie :is() und :where() .

Die folgenden Regeln liefern das gleiche Ergebnis in unterstützenden Browsern:

 article :not(h2):not(h3):not(h4) { margin-bottom: 1.5em; } article :not(h2, h3, h4) { margin-bottom: 1.5em; }

Die Fähigkeit von :not() , eine Auswahlliste zu akzeptieren, wird von modernen Browsern hervorragend unterstützt.

Wie wir bei :is() gesehen haben, kann erweitertes :not() auch einen Verweis auf den Basisselektor als Nachkomme mit * enthalten. Dieser CodePen demonstriert diese Fähigkeit, indem er Links auswählt, die keine Nachkommen von nav sind.

Siehe Pen [Testing :not() with a descendent selector](https://codepen.io/smashingmag/pen/BapvQQv) von Stephanie Eckles.

Siehe Pen Testing :not() with a descendent selector von Stephanie Eckles.

Bonus : Die vorherige Demo enthält auch ein Beispiel für die Verkettung von :not() und :is() , um Bilder auszuwählen, die keine benachbarten Geschwister von entweder h2 oder h3 Elementen sind.

Vorgeschlagen, aber „gefährdet“ — :has()

Die letzte Pseudo-Klasse, die ein sehr aufregender Vorschlag ist, aber von keinem aktuellen Browser implementiert wird, auch nur auf experimentelle Weise, ist :has() . Tatsächlich wird es im Editor's Draft von Selector Level 4 als „gefährdet“ aufgeführt, was bedeutet, dass es anerkanntermaßen Schwierigkeiten beim Abschluss seiner Implementierung hat und daher aus der Empfehlung gestrichen werden kann .

Wenn implementiert, wäre :has() im Wesentlichen der „Elternselektor“, nach dem sich viele CSS-Leute gesehnt haben. Es würde mit einer Logik ähnlich einer Kombination aus :focus-within und :is() mit nachkommenden Selektoren funktionieren, bei der Sie nach dem Vorhandensein von Nachkommen suchen, aber das angewendete Styling auf das übergeordnete Element bezogen wäre.

Wenn die Navigation eine Schaltfläche enthielt, hätte die Navigation gemäß der folgenden Regel die obere und untere Polsterung verringert:

 nav { padding: 0.75rem 0.25rem; nav:has(button) { padding-top: 0.25rem; padding-bottom: 0.25rem; }

Auch dies ist derzeit in keinem Browser implementiert, auch nicht experimentell – aber es macht Spaß, darüber nachzudenken! Robin Rendle gab auf CSS-Tricks weitere Einblicke in diesen zukünftigen Selektor.

Lobende Erwähnung von Level 3: :empty

Eine nützliche Pseudo-Klasse, die Sie möglicherweise aus Selectors Level 3 übersehen haben, ist :empty , die auf ein Element passt, wenn es keine untergeordneten Elemente hat, einschließlich Textknoten.

Die Regel p:empty passt auf <p></p> aber nicht auf <p>Hello</p> .

Eine Möglichkeit, :empty zu verwenden, besteht darin, Elemente auszublenden, die möglicherweise Platzhalter für dynamische Inhalte sind, die mit JavaScript gefüllt sind. Vielleicht haben Sie ein div, das Suchergebnisse empfängt, und wenn es gefüllt ist, hat es einen Rahmen und etwas Polsterung. Aber ohne noch keine Ergebnisse möchten Sie nicht, dass es Platz auf der Seite einnimmt. Mit :empty können Sie es ausblenden mit:

 .search-results:empty { display: none; }

Möglicherweise denken Sie darüber nach, eine Nachricht im leeren Zustand hinzuzufügen, und sind versucht, sie mit einem Pseudo-Element und einem content hinzuzufügen. Der Fallstrick dabei ist, dass Nachrichten möglicherweise nicht für Benutzer von Hilfstechnologien verfügbar sind, die uneinheitlich sind, ob sie auf content zugreifen können. Mit anderen Worten, um sicherzustellen, dass auf eine Meldung vom Typ „Keine Ergebnisse“ zugegriffen werden kann, möchten Sie diese als echtes Element wie einen Absatz hinzufügen (ein aria-label wäre für ein verstecktes div nicht mehr zugänglich).

Ressourcen zum Erlernen von Selektoren

CSS hat viel mehr Selektoren, einschließlich Pseudoklassen. Hier sind ein paar weitere Orte, an denen Sie mehr darüber erfahren können, was verfügbar ist:

  • Die Dokumentation der MDN CSS-Selektoren enthält eine umfassende kategorisierte Liste;
  • Ich habe eine zweiteilige Anleitung für fortgeschrittene CSS-Selektoren geschrieben, Sie können mit Teil eins beginnen;
  • Viel Spaß beim Erlernen von CSS-Selektoren mit dem Spiel CSS Diner;
  • Kitty Giraudel hat ein Selektor-Erklärungstool erstellt, das Teile eines bereitgestellten Selektors aufschlüsselt und beschreibt.