Es gibt eine zunehmende Anzahl von „benutzerdefinierten“ Funktionen auf der Webplattform. Wir haben benutzerdefinierte Eigenschaften (--meine-eigenschaft), benutzerdefinierte Elemente (<mein-element>) und benutzerdefinierte Ereignisse (new CustomEvent('meinEreignis')). Irgendwann erhalten wir vielleicht sogar benutzerdefinierte Media Queries (@media (--meine-Medien)).
Aber das ist noch nicht alles! Möglicherweise haben Sie es verpasst, da es in Googles Artikel „Neu in Chrome 90“ nicht erwähnt wurde (um fair zu sein, declarative shadow DOM hat die Show in dieser Version gestohlen), aber Chrome hat gerade Unterstützung für eine weitere „benutzerdefinierte“ Funktion hinzugefügt: benutzerdefinierte Zustands-Pseudo-Klassen (:--mein-zustand).
Eingebaute Zustände
Bevor wir über benutzerdefinierte Zustände sprechen, werfen wir einen kurzen Blick auf die eingebauten Zustände, die für eingebaute HTML-Elemente definiert sind. Das CSS Selectors Modul und der Abschnitt „Pseudo-Klassen“ des HTML Standards definieren eine Reihe von Pseudo-Klassen, die verwendet werden können, um Elemente in verschiedenen Zuständen abzugleichen. Die folgenden Pseudo-Klassen werden heute in den Browsern weitgehend unterstützt
| Benutzeraktion | |
|---|---|
:hover |
der Mauszeiger schwebt über dem Element |
:active |
das Element wird vom Benutzer aktiviert |
:focus |
das Element hat den Fokus |
:focus-within |
das Element hat den Fokus oder enthält ihn |
| Position | |
:visited |
der Link wurde vom Benutzer besucht |
:target |
das Element wird durch das Fragment der Seiten-URL adressiert |
| Eingabe | |
:disabled |
das Formularelement ist deaktiviert |
:placeholder-shown |
das Eingabeelement zeigt Platzhaltertext an |
:checked |
die Checkbox oder Radio-Schaltfläche ist ausgewählt |
:invalid |
der Wert des Formularelements ist ungültig |
:out-of-range |
der Wert des Eingabeelements ist außerhalb des angegebenen Bereichs |
:-webkit-autofill |
das Eingabeelement wurde vom Browser automatisch ausgefüllt |
| Andere | |
:defined |
das benutzerdefinierte Element wurde registriert |
Hinweis: Aus Gründen der Kürze wurden einige Pseudo-Klassen weggelassen und einige Beschreibungen erwähnen nicht alle möglichen Anwendungsfälle.
Benutzerdefinierte Zustände
Ähnlich wie eingebaute Elemente können benutzerdefinierte Elemente verschiedene Zustände haben. Eine Webseite, die ein benutzerdefiniertes Element verwendet, möchte diese Zustände möglicherweise stylen. Das benutzerdefinierte Element könnte seine Zustände über CSS-Klassen (class Attribut) auf seinem Host-Element verfügbar machen, aber das gilt als Anti-Pattern.
Chrome unterstützt jetzt eine API zum Hinzufügen interner Zustände zu benutzerdefinierten Elementen. Diese benutzerdefinierten Zustände werden über benutzerdefinierte Zustands-Pseudo-Klassen für die äußere Seite verfügbar gemacht. Zum Beispiel kann eine Seite, die ein <live-score> Element verwendet, Stile für den benutzerdefinierten --loading Zustand dieses Elements deklarieren.
live-score {
/* default styles for this element */
}
live-score:--loading {
/* styles for when new content is loading */
}
Fügen wir einem <labeled-checkbox>-Element einen --checked-Zustand hinzu
Die Spezifikation Custom State Pseudo Class enthält ein vollständiges Codebeispiel, das ich zur Erklärung der API verwenden werde. Der JavaScript-Teil dieser Funktion befindet sich in der Klassendefinition des benutzerdefinierten Elements. Im Konstruktor wird ein „Element-Internals“-Objekt für das benutzerdefinierte Element erstellt. Anschließend können benutzerdefinierte Zustände im internen states-Objekt gesetzt und aufgehoben werden.
Beachten Sie, dass die ElementInternals API sicherstellt, dass die benutzerdefinierten Zustände für die Außenwelt schreibgeschützt sind. Mit anderen Worten, die äußere Seite kann die internen Zustände des benutzerdefinierten Elements nicht ändern.
class LabeledCheckbox extends HTMLElement {
constructor() {
super();
// 1. instantiate the element’s “internals”
this._internals = this.attachInternals();
// (other code)
}
// 2. toggle a custom state
set checked(flag) {
if (flag) {
this._internals.states.add("--checked");
} else {
this._internals.states.delete("--checked");
}
}
// (other code)
}
Die Webseite kann nun die internen Zustände des benutzerdefinierten Elements über benutzerdefinierte Pseudo-Klassen mit demselben Namen stylen. In unserem Beispiel wird der --checked-Zustand über die :--checked-Pseudo-Klasse verfügbar gemacht.
labeled-checkbox {
/* styles for the default state */
}
labeled-checkbox:--checked {
/* styles for the --checked state */
}
Diese Funktion ist (noch) kein Standard
Browserhersteller diskutieren seit drei Jahren, wie die internen Zustände von benutzerdefinierten Elementen über benutzerdefinierte Pseudo-Klassen verfügbar gemacht werden können. Googles Custom State Pseudo Class Spezifikation bleibt ein „inoffizieller Entwurf“, der von WICG gehostet wird. Die Funktion hat eine Design-Überprüfung im W3C TAG durchlaufen und wurde an die CSS Working Group übergeben. In der Chrome-Diskussion „intent to ship“ schrieb Mounir Lamouri
Es scheint, dass diese Funktion eine gute Unterstützung hat. Es klingt, als ob es für Webentwickler schwierig sein könnte, davon zu profitieren, solange sie nicht weit verbreitet ist, aber hoffentlich werden Firefox und Safari folgen und sie ebenfalls implementieren. Jemand muss sie zuerst implementieren, und da es keine abwärtskompatiblen Änderungen absehbar sind, klingt es sicher, zuerst zu gehen.
Nun müssen wir auf die Implementierungen in Firefox und Safari warten. Die Browser-Bugs wurden eingereicht (Mozilla #1588763 und WebKit #215911), haben aber bisher wenig Aufmerksamkeit erhalten.
Leider ist dies wieder nur eine halbfertige Lösung für unser Problem.
Mein Hauptproblem hier ist, dass es eng mit dem Shadow-Root gekoppelt ist und nur das Host-Element und nicht ein bestimmtes Kind davon zustandsabhängig gemacht werden kann.
Betrachten Sie folgendes Problem
Sie haben einen Schieberegler, und dieser Schieberegler generiert eine Paginierungsliste. Innerhalb dieser Liste gibt es mehrere Listenelemente und in jedem Listenelement befindet sich eine Schaltfläche.
Nun möchten Sie dieses Element als :–selected markieren, damit der Benutzer die Schaltfläche innerhalb des ausgewählten Elements entsprechend stylen kann. Leider ist dies weder mit benutzerdefinierten Pseudo-Zuständen (da es an Ihren Schieberegler gebunden ist) noch mit benutzerdefinierten Pseudo-Elementen (d.h.
partAttribut) möglich (da dies keine positionsbezogenen Selektoren zulässt).Wir waren etwas Nützlichem so nahe...