CSS hat noch keine switch-Regel oder bedingte if-Anweisung, abgesehen von der spezifischen Natur von @media-Abfragen und einigen tiefen Tricksereien mit CSS Custom Properties. Werfen wir einen Blick darauf, warum dies nützlich wäre, und betrachten wir einen Trick, der heute anwendbar ist, um es zu ermöglichen.
Aktuelle Diskussionen über die Möglichkeit
Obwohl nichts davon heute verwendbar ist, gab es im letzten Jahr eine gute Menge an Diskussionen über das Konzept von generischen bedingten CSS.
- Brian Kardell schlug eine
switch()-Anweisung vor und Tab Atkins baute darauf auf. - Jonathan Neal schlug eine Media-Query-Variante für bedingte Werte vor, die eine ganze Menge an Konversation auslöste.
- Lea Verou schlug „höherwertige Custom Properties vor“ (hier ist ein Blick darauf von Bramus Van Damme), die außergewöhnlich nützlich erscheinen.
Also, ja. Die Nachfrage nach bedingtem CSS ist vorhanden.
Stellen Sie sich vor, warum bedingtes CSS nützlich wäre
Vielleicht eine visuelle Änderung nach einer bestimmten Scroll-Menge. Eine visuelle Änderung, nachdem eine numerische Eingabe innerhalb eines bestimmten Bereichs liegt. Eine Komponente mit einer Handvoll Zuständen.
Es gibt ein ganzes Genre extrem beliebter JavaScript-Bibliotheken für Benutzeroberflächen (z. B. React, Vue usw.), die im Wesentlichen zum Erstellen von Benutzeroberflächen basierend auf Zuständen dienen. Dies ist eindeutig ein Bedarf der Entwickler. Wenn wir diese zustandsbasierte Formatierung nach CSS verschieben könnten, bräuchten wir weniger JavaScript – und vielleicht eine bessere Trennung der Zuständigkeiten.
Ein gemeinsames Thema
Wir haben bereits Custom Properties in CSS und könnten zustandsänderungslogik auf ihnen basieren lassen, wodurch ein Block von Stilen als Nebenwirkung der Änderung der Custom Property auf bestimmte Werte geändert wird.
Es stimmt, dass wir bereits Mechanismen zur Änderung von Stilblöcken haben. Wir können class über JavaScript ändern, und diese class kann alles anwenden, was wir in CSS möchten. Aber das bedeutet nicht, dass zustandsbasierte Formatierung in CSS nicht nützlich wäre. Wir haben nicht immer die Möglichkeit oder möchten vielleicht kein JavaScript dafür schreiben und stattdessen Custom Properties auf andere Weise ändern (z. B. durch Media Queries, HTML-Änderungen usw.). Dies in CSS zu tun, hilft bei der Trennung von Geschäftslogik und visueller Stil-Logik.
Ein Trick! @keyframes für den Zustand verwenden
CSS @keyframes kann verwendet werden, um spezifische Änderungen zu wechseln. Durch die Macht der animation-Eigenschaft eröffnet sich die Möglichkeit, genau auszuwählen, welcher Frame angezeigt werden soll, und ihn *genau* auf diesem Frame zu pausieren, wodurch effektiv eine Switch-Case-Anweisung oder zustandsbasierte Stile nachgeahmt werden.
Schauen wir uns das in Aktion an, indem wir mit der Eigenschaft animation-delay spielen.
Hier ist, was in diesem Pen passiert.
animation-delay: Negative Verzögerungswerte zwingen einen spezifischen Frame (oder dazwischen) zur Wirkung (positive Werte funktionieren nicht so). Wir werden diesen Trick verwenden, um Zustände zu erzwingen.animation-play-state: paused: Wir animieren eigentlich nichts, daher bleibt die Animation pausiert.animation-duration: Die tatsächliche Dauer spielt keine Rolle, sie benötigt nur eine, damit ein Zeitrahmen für die verschiedenen Keyframes vorhanden ist. Wir machen sie zu einem Wert wie100.001s, damit auch bei einer Verzögerung von100sder letzte Keyframe noch funktioniert. Die Dauer muss länger sein als der Verzögerungswert.
Das erste Range-Input modifiziert die animation-delay zwischen einem Bereich von -100s und 0s.
Ein Anwendungsfall aus der Praxis
Bevor wir direkt zum funktionierenden Beispiel übergehen, lohnt es sich, diesen Trick genauer zu besprechen, da es einige Nuancen gibt, die Sie beachten sollten.
Erstens funktioniert der Trick nur mit numerischen Werten. Also, Farbwerte oder Zeichenketten, da er streng mathematisch arbeitet.
Zweitens gibt es den booleschen Trick. Betrachten Sie eine Variable --value: 10, die jeden numerischen Wert zwischen 0 und 100 annehmen kann. Wir möchten eine Farbe anwenden, wenn der Wert größer als 5 ist. Woher wissen wir, ob der Wert größer oder kleiner als 5 ist? Und selbst wenn wir es wissen, wie hilft uns das wirklich?
--is-above-5: clamp(0, var(--value) - 5, 1)
--wert | --ist-größer-als-5 | Ergebnis |
|---|---|---|
| 0 | 0 | 0 – 5 = -5, clamp() erzwingt einen Wert, der nicht kleiner als 0 ist |
| 2 | 0 | 2 – 5 = -3, clamp() erzwingt einen Wert, der nicht kleiner als 0 ist |
| 5 | 0 | 5 – 5 = 0 |
| 7 | 1 | 7 – 5 = 2, clamp() erzwingt einen Wert, der nicht größer als 1 ist |
clamp() ist wie ein intelligenteres calc(), da es uns erlaubt, einen berechneten Wert streng auf einen Bereich zu beschränken, während wir einen idealen Wert deklarieren. Dieser Bereich ist alles, was benötigt wird, um eine boolesche Variable zu erreichen.
Schreiben Sie jede Mathematik in den zweiten Parameter von clamp(), und dies gibt entweder 0 (oder kleiner) oder 1 (oder größer) aus. Achten Sie darauf, keine Mathematik zu schreiben, die zu einer Zahl zwischen 0 und 1 führen könnte.
So funktioniert das.
Das Range-Input-Feld hat nur die Aufgabe, seinen Wert zu „senden“, indem es Werte für --value, --min und --max definiert und dann --value mit einem oninput-Ereignis modifiziert. Das ist das Minimalste, was getan werden kann, um zustandsähnliches Verhalten in CSS zu erzielen. Kein JavaScript erforderlich.
Mit CSS-Mathematikfunktionen ist es möglich, den „abgeschlossenen“ Prozentsatz des Fortschrittsbalkens aus denselben Variablen abzuleiten.
--completed: calc((var(--value) - var(--min) ) / (var(--max) - var(--min)) * 100);
Jetzt wissen wir, ob der Wert über einem bestimmten Prozentsatz liegt, was uns eine weitere Möglichkeit gibt, Änderungen nach Zustand vorzunehmen.
--over-30: clamp(0, var(--completed) - 30, 1);
--over-70: clamp(0, var(--completed) - 70, 1);
/* ...and so on... */
Okay, großartig, aber wie können wir dies verwenden, um einen bestimmten Keyframe auszuwählen? Durch die Verwendung der max()-Funktion.
--frame: max(
calc(1 - var(--over-30)),
var(--over-30) * 2,
var(--over-70) * 3,
var(--is-100) * 4
);
Das Problem bei CSS-Booleans ist, dass es viele Wege gibt, sie zu verwenden, um ein bestimmtes Ziel zu erreichen, und man muss kreativ werden und eine Formel finden, die kurz und lesbar ist.
In der obigen Formel „schalten“ die Booleans eine Frame-Nummer um, wenn der Boolean den Wert 1 hat. Da wir eine max-Funktion verwenden, wird die größte umgeschaltete Frame-Nummer der berechnete Wert von --frame sein.
Beachten Sie, dass die Farbänderung eine leichte Übergangszeit hat. Wir hätten dies mit background: currentColor; auf dem Füllbereich tun können, der die Farbe vom Elternteil erbt, aber ich habe mich entschieden, CSS Houdini zu verwenden, um die Macht der Zuweisung von Übergängen zu CSS-Variablen zu veranschaulichen, indem sein type deklariert wird.
Ein Beispiel für einen intensiv genutzten **CSS-Booleschen Trick** kann im folgenden Pen gesehen werden, der eine rein CSS-basierte Komponente mit vielen Variablen ist, die eine breite Palette von Anpassungen ermöglichen.
Ich bin sicher, dass es viele weitere Anwendungsfälle für diesen kleinen Trick gibt und bin gespannt, was die Kreativität der Community noch erreichen kann.
Doch der oninput-Handler ist JS, und das Schlimmste, die Eval-Art.
Es wäre nützlich, wenn wir Bedingungen und Zugriff auf einige DOM-Eigenschaften in CSS hätten, aber andererseits, genauso wie es infuriierend ist, seltsame Inline-Event-Handler zu finden, stellen Sie sich vor, Sie müssten eine Codebasis verwalten, bei der die Logik gleichzeitig in JS, HTML und CSS vorhanden sein kann. Wir brauchen viel fortgeschrittenere CSS-Linter ;p
@MS – es ist nur ein Beispiel für einen Anwendungsfall, den ich persönlich nutze. Ich sehe absolut kein Problem mit Inline-Events für einfache Komponenten, die als Black-Box funktionieren und betrachtet werden sollten, bei denen andere Entwickler nicht einmal wissen sollten, was vor sich geht.
Stellen Sie es sich wie eine Web-Komponente vor, die das ultimative Beispiel für eine Black-Box ist, und dann wissen Sie einfach nicht und kümmern sich nicht darum, wie sie das tut, was sie tut, Sie kümmern sich nur darum, dass sie für Sie gut funktioniert.
Jedenfalls ist die oben beschriebene Methode für hochkomplexe Szenarien.
Stellen Sie sich vor, Sie haben bereits eine Komponente, die Berechnungen durchführt, und Sie möchten diese Berechnungen in verschiedene CSS-Stile „übersetzen“, abhängig von einigen Parametern. zum Beispiel ein Scroll-Event-Listener, und mit dem scrollTop-Wert können Sie diesen Wert einfach an das CSS übergeben, und jetzt hat das CSS plötzlich Zugriff auf dynamische Daten, was die Tür zu vielen Möglichkeiten öffnet, wie im Artikel beschrieben.
Es gibt so viele Dinge, die Sie damit tun können, über die ich noch nicht nachgedacht habe. Ich habe einfach ein Werkzeug erfunden, und jetzt ist es an den Leuten, Wege zu finden, es zu nutzen.
Wie ein Hacker sitze ich seit Jahren, fast 20, und denke – wie kann ich CSS manipulieren, um Dinge zu tun, für die seine Schöpfer es nicht verwenden würden? Ich möchte CSS bis zum Äußersten manipulieren, es meinem Willen beugen, es an die Grenzen zwingen, die an mein Wissen über die Sprache und meine Vorstellungskraft gebunden sind, und Vorstellungskraft ist der Schlüssel, um diese CSS-Tricks zu finden.
Vielen Dank für das Ausreizen der Grenzen.
Ich sehe hier ein unglaubliches Potenzial für die Vereinfachung der Verwaltung von Farbschemata. Anstatt Dutzende von Eigenschaften festzulegen, jedes Mal, wenn Sie ein Farbschema aufrufen möchten, können Sie sich mit einer Zeile auf einen Frame aus der Farbschema-Animation beziehen: https://codepen.io/jproffitt71/pen/bGBMVJx
Das alles lässt mich fragen, ob CSS etwas wie ein @properties-Schlüsselwort für die Definition von Gruppen von Custom Properties haben sollte.
Ah, ich sehe, Sie verweisen gleich zu Beginn auf einen Vorschlag dafür: https://github.com/w3c/csswg-drafts/issues/5624
Mein Fehler. Das ist aber sehr aufregend.