Vor ein paar Wochen schrillten einige Alarmglocken, als die CSS Working Group (CSSWG) beschloss, eine if()-Bedingung zur Spezifikation des CSS Values Module Level 5 hinzuzufügen. Es war Lea Verous X-Post am selben Tag, der meine Aufmerksamkeit erregte
Ein historischer Tag für CSS 😀🎉
— Lea Verou (@LeaVerou) 13. Juni 2024
Wenn Sie Komponenten schreiben, die von anderen verwendet und/oder gestaltet werden, wissen Sie, wie riesig das ist!
background: if(style(–variant: success), var(–green));
Selbst wenn nicht, wird dies Dinge ermöglichen wie
padding: if(var(–2xl), 1em, var(–xl) or var(–m),… pic.twitter.com/cXeqwBuXvK
Lea ist diejenige, die das GitHub-Issue eröffnet hat, das zur Diskussion führte, und durch einen Zufall – oder vielleicht Schicksal – kam der Beschluss genau an ihrem Geburtstag. Das muss ein turbulenter Tag gewesen sein! Was hast du zum Geburtstag bekommen? „Oh, weißt du, nur einen angenommenen Vorschlag für die CSS-Spezifikation.“ Wahnsinn, einfach Wahnsinn.
Der angenommene Vorschlag ist grünes Licht für die CSSWG, an der Idee zu arbeiten, mit der Absicht, einen Spezifikationsentwurf für weiteres Feedback in Umlauf zu bringen, damit daraus hoffentlich ein empfohlenes CSS-Feature wird. Es wird also noch eine ganze Weile dauern, bis das Ganze spruchreif ist – also falls es jemals fertiggestellt wird.
Aber die Idee, Stile basierend auf einer bedingten Anforderung anzuwenden, ist extrem spannend und einen frühen Blick wert. Ich habe am selben Tag, an dem Lea auf X postete, einige Notizen dazu in meinem Blog verfasst und dachte mir, ich fasse diese hier für die Nachwelt zusammen und ergänze weitere Details, die seitdem aufgetaucht sind.
Dies ist keine neue Idee
Viele Vorschläge entstehen aus zuvor abgelehnten Ideen, und if() ist da keine Ausnahme. Tatsächlich haben wir in letzter Zeit mehrere CSS-Funktionen erhalten, die bedingtes Styling ermöglichen – :has() und Container Style Queries sind zwei der offensichtlichsten Beispiele. Lea zitiert sogar ein Ticket von 2018, das dem nun angenommenen Vorschlag sehr ähnlich sieht.
Der Unterschied?
Style Queries wurden bereits veröffentlicht, und wir konnten uns einfach auf dieselbe Syntax für Bedingungen beziehen (plus
Lea Verou, „Inline conditionals in CSS?“media()undsupports()aus Tabs@when-Vorschlag), während im Vorschlag von 2018 die Funktionsweise von Bedingungen weitgehend undefiniert war.
Mir gefällt, wie Lea aufzeigt, dass CSS schon immer eine bedingte Sprache war
Leute... CSS hatte von Anfang an Bedingungen. Jeder Selektor ist im Grunde eine Bedingung!
Lea Verou, „Inline conditionals in CSS?“
Stimmt! Die Kaskade ist das Instrument, um Selektoren auszuwerten und sie den HTML-Elementen auf einer Seite zuzuordnen. Was if() mitbringt, ist eine Möglichkeit, Inline-Bedingungen direkt bei den Werten zu schreiben.
Syntax
Es läuft auf Folgendes hinaus
<if()> = if( <container-query>, [<declaration-value>]{1, 2} )
…wobei
- Werte können verschachtelt werden, um mehrere Zweige zu erzeugen.
- Wenn kein drittes Argument angegeben wird, entspricht dies einem leeren Token-Stream.
All dies ist im Moment rein konzeptionell und nichts ist in Stein gemeißelt. Es ist wahrscheinlich, dass sich Dinge ändern, während die CSSWG an dem Feature arbeitet. Nach aktuellem Stand dreht sich die Idee jedoch darum, eine Bedingung anzugeben und einen von zwei deklarierten Stilen festzulegen – einen als „Standard“-Stil und einen als „aktualisierten“ Stil, wenn die Bedingung zutrifft.
.element {
background-color:
/* If the style declares the following custom property: */
if(style(--variant: success),
var(--color-green-50), /* Matched condition */
var(--color-blue-50); /* Default style */
);
}
In diesem Fall suchen wir nach einer style()-Bedingung, bei der eine CSS-Variable namens --variant deklariert und auf den Wert success gesetzt ist, und
- …wenn
--variantaufsuccessgesetzt ist, setzen wir den Wert vonsuccessauf--color-green-50, eine Variable, die auf einen grünlichen Farbwert verweist. - …wenn
--variantnicht aufsuccessgesetzt ist, setzen wir den Wert vonsuccessauf--color-blue-50, eine Variable, die auf einen bläulichen Farbwert verweist.
Der Standardstil wäre optional, daher denke ich, dass er in einigen Fällen für eine etwas bessere Lesbarkeit weggelassen werden kann
.element {
background-color:
/* If the style declares the following custom property: */
if(style(--variant: success),
var(--color-green-50) /* Matched condition */
);
}
Die Syntaxdefinition oben erwähnt, dass wir ein drittes Argument zusätzlich zur erfüllten Bedingung und dem Standardstil unterstützen könnten, was es uns ermöglicht, Bedingungen in Bedingungen zu verschachteln
background-color: if(
style(--variant: success), var(--color-success-60),
if(style(--variant: warning), var(--color-warning-60),
if(style(--variant: danger), var(--color-danger-60),
if(style(--variant: primary), var(--color-primary)
)
),
)
);
Uff, das sieht nach einer wilden Verschachtelung aus! Lea schlägt daraufhin eine Syntax vor, die zu einer viel flacheren Struktur führen würde
<if()> = if(
[ <container-query>, [<declaration-value>]{2} ]#{0, },
<container-query>, [<declaration-value>]{1, 2}
)
Mit anderen Worten: Verschachtelte Bedingungen sind viel flacher, da sie außerhalb der ursprünglichen Bedingung deklariert werden können. Dasselbe Konzept wie zuvor, aber eine andere Syntax
background-color: if(
style(--variant: success), var(--color-success-60),
style(--variant: warning), var(--color-warning-60),
style(--variant: danger), var(--color-danger-60),
style(--variant: primary), var(--color-primary)
);
Anstatt also eine if()-Anweisung innerhalb einer anderen if()-Anweisung zu haben, können wir alle möglichen passenden Bedingungen in einer einzigen Anweisung zusammenfassen.
Dies hängt alles mit Style Queries zusammen
Wir versuchen, eine if()-Bedingung zu erfüllen, indem wir die Stile eines Elements abfragen. Es gibt keine entsprechende size()-Funktion zur Abfrage von Dimensionen – Container Queries setzen Größe implizit voraus
.element {
background: var(--color-primary);
/* Condition */
@container parent (width >= 60ch) {
/* Applied styles */
background: var(--color-success-60);
}
}
Und Container Queries werden zu Style Queries, wenn wir stattdessen die style()-Funktion aufrufen
.element {
background: orangered;
/* Condition */
@container parent style(--variant: success) {
/* Applied styles */
background: dodgerblue;
}
}
Style Queries ergeben für mich viel mehr Sinn, wenn man sie im Kontext von if() betrachtet. Ohne if() kann man die allgemeine Nützlichkeit von Style Queries leicht in Frage stellen. Aber in diesem Licht wird klar, dass Style Queries Teil eines viel größeren Bildes sind, das über reine Container Queries hinausgeht.
Bei der if()-Syntax gibt es noch viel zu klären. Zum Beispiel beschreibt Tab Atkins ein mögliches Szenario, das zu Verwirrung darüber führen könnte, was die zutreffende Bedingung und was die Standardstil-Parameter sind. Wer weiß also, wie das Ganze am Ende ausgeht!
Bedingungen, die andere Bedingungen unterstützen
Wie wir bereits festgestellt haben, ist if() bei weitem nicht die einzige Art von bedingter Prüfung in CSS. Wie würde es aussehen, eine Inline-Bedingung zu schreiben, die andere Bedingungen wie @supports und @media prüft?
Im Code
background-color: if(
supports( /* etc. */ ),
@media( /* etc. */ )
);
Die Herausforderung bestünde darin, dass Container Größenabfragen unterstützen. Wie bereits erwähnt, gibt es keine explizite size()-Funktion; stattdessen verhält sie sich eher wie eine anonyme Funktion.
@andruud hat die Herausforderung in der GitHub-Diskussion treffend beschrieben
Ich sehe nicht, warum wir nicht
supports()undmedia()machen könnten, aber Größenabfragen würden Zyklen mit dem Layout verursachen, die schwer oder gar unmöglich zu erkennen sind. (Das ist der Grund, warum wir überhaupt die Einschränkungen brauchten, die wir derzeit für Größen-CQs haben.)
„Können wir das nicht schon mit dem [X]-Ansatz machen?“
Als wir uns vorhin die Syntax angesehen haben, ist Ihnen vielleicht aufgefallen, dass es bei if() genauso sehr um Custom Properties geht wie um Bedingungen. Über die Jahre sind mehrere Workarounds entstanden, um das zu imitieren, was wir gewinnen würden, wenn wir den Wert einer Custom Property bedingt setzen könnten, darunter:
- Die Verwendung von Custom Properties als Boolean, um Stile anzuwenden oder nicht, je nachdem, ob sie gleich
0oder1sind. (Ana hat dazu einen wunderbaren Artikel geschrieben.) - Die Verwendung einer Platzhalter-Custom-Property mit leerem Wert, die gesetzt wird, wenn eine andere Custom Property gesetzt ist, d.h. „der Custom Property Toggle-Trick“, wie Chris ihn beschreibt.
- Container Style Queries! Das Problem (neben der mangelnden Implementierung) ist, dass Container Stile nur auf ihre Nachfahren anwenden, d. h. sie können Stile nicht auf sich selbst anwenden, wenn sie eine bestimmte Bedingung erfüllen, sondern nur auf ihren Inhalt.
Lea geht in einem separaten Post mit dem Titel „Inline conditional statements in CSS, now?“ tief darauf ein. Er enthält eine Tabelle, die Ansätze skizziert und vergleicht, die ich hier einfach einfüge. Die Erklärungen stecken voller komplexer CSS-Nerderie, sind aber extrem hilfreich, um die Notwendigkeit von if() zu verstehen und zu sehen, wie es im Vergleich zu den cleveren „Hacks“ abschneidet, die wir jahrelang verwendet haben.
| Methode | Eingabewerte | Ausgabewerte | Pro | Contra |
|---|---|---|---|---|
| Binäre lineare Interpolation | Zahlen | Quantitativ | Kann als Teil eines Wertes verwendet werden | Begrenzter Ausgabebereich |
| Toggles | var(--alias) (tatsächliche Werte sind zu seltsam, um sie direkt offenzulegen) | Alle | Kann in einem Teil eines Wertes verwendet werden | Seltsame Werte, die aliased werden müssen |
| Pausierte Animationen | Zahlen | Alle | Normale, entkoppelte Deklarationen | Übernimmt die animation-EigenschaftKaskaden-Kuriositäten |
| Type Grinding | Keywords | Jeder vom syntax-Deskriptor unterstützte Wert | Hohe Flexibilität für exponierte APIGute Kapselung | CSS muss in das Light DOM eingefügt werden Mühsamer Code (kann aber mit Build-Tools automatisiert werden) Keine Firefox-Unterstützung (obwohl sich das gerade ändert) |
| Variabler Animationsname | Keywords | Alle | Normale, entkoppelte Deklarationen | Unpraktisch außerhalb des Shadow DOM aufgrund von Namenskonflikten Übernimmt die animation-EigenschaftKaskaden-Kuriositäten |
Alles Gute zum Geburtstag, Lea!
Zwei Wochen zu spät, aber danke, dass du die Geschenke deines großen Tages mit uns teilst! 🎂
Referenzen
- Was ist das MVP für Inline-Conditionals bei Custom Properties? (Lea Verou, GitHub Issue #10064)
- Inline-Conditionals in CSS? (Lea Verou)
- Inline-Conditionals in CSS, jetzt schon? (Lea Verou)
Abgesehen davon, dass man so etwas nicht braucht, wird dies ein schrecklicher Tag für CSS, falls es implementiert wird. Das Gute an CSS ist, dass es noch relativ unbeschadet von Einflüssen naiver Programmierer ist – aber dies hinzuzufügen, wird die Schleusen für alle Arten von dummen Zeug öffnen.
Als nächstes wird irgendein Idiot einen Webserver aus CSS programmieren, und dies wird eine neue Ära von super-abstrahierten, undurchschaubaren UI-Frameworks einläuten, die irgendeine Node-Erweiterung benötigen, um zu laufen, und einen Webserver-Neustart bei jeder Änderung erfordern, was Entwickler weiter davon abhält, tatsächlich CSS zu lernen.
Wenn es da draußen einen Entwickler gibt, der tatsächlich glaubt, dass dies ein Gewinn für CSS ist, dann sollte er wahrscheinlich kein CSS schreiben. Bleibt bei Java oder C, denn ihr hättet keine Ahnung, wie man ein Layout codiert, wenn euer Leben davon abhinge.
Es wurde bereits getan: https://dev.to/thormeier/dont-try-this-at-home-css-as-the-backend-what-3oih
Ich habe noch nie If-Bedingungen in CSS benötigt. Ich denke, das widerspricht dem, wofür CSS gedacht ist: ein Cascading Stylesheet... wobei „cascading“ (kaskadierend) hier das Schlüsselwort ist. Dies verkompliziert eine einfache und schöne Sprache weiter zu etwas, das sie nicht sein soll. KISS (Keep It Simple, Stupid).
Stimme allen Kommentaren zu, völlig seltsamer Hype um eine vollkommen sinnlose Abstraktion.
Wer, bitteschön, wird den Wert der Success-Variablen auf true oder false setzen?
Ja, derselbe Code, der bisher dazu diente, einen Klassennamen umzuschalten oder die Stile bedingt zu ändern.
All das führt nur dazu, dass Entwickler verwirrt sind, wo sie bei Fehlern suchen sollen, da die Funktionalität jetzt entweder in CSS oder im Code liegen könnte.
Es wird auch das Testen von Funktionalität ein Stück weit schwieriger machen.
Mein Gehirn tut weh!
Allerdings benutze ich seit Jahren Bedingungen in meinem Sass-Code. Zum Beispiel die Übergabe von Argumenten in Mixins und das Testen ihrer Werte.
Hoffentlich wird dieses native Verhalten eines Tages Realität... aber ohne eine Art „Frankenstein“-Syntax zu erschaffen, um es zu erreichen.
Einige andere Kommentare decken fast alles ab, was ich an der Arbeit in diesem Bereich hasse. Sie sind kurzsichtig, rechthaberisch, basieren ausschließlich auf den eigenen Bedürfnissen und einige sind sogar feindselig gegenüber anderen.
Habt ihr überhaupt versucht, es aus anderen Blickwinkeln zu betrachten? Habt ihr versucht, praktische Anwendungsfälle außerhalb eurer aktuellen Bubble zu finden? Einer der Vorteile könnte durchaus sein, endlich nicht mehr von bestimmten CSS/JS-Frameworks abhängig zu sein. Es könnte der nächste Schritt in Richtung Vanilla-Webentwicklung sein. Hin zu einfacher zu implementierenden Styled Web Components. Hin zu einfach einzurichtenden, voll anpassbaren Themes. Hin zu noch mehr DRY (Don't Repeat Yourself), kompaktem CSS.
Ehrlich gesagt sehe ich viel mehr Vor- als Nachteile. Meine Bedenken liegen eher auf der Seite von Performance und Syntax. Aber genau dafür ist die Working Group da: um diese Dinge entweder zu klären oder zu sagen: „Nein, den Aufwand nicht wert“.
Diese Kommentare wirken wie voreilige Rufe nach Stillstand; Veränderung ist nicht willkommen. Wäre diese Einstellung vorherrschend, säßen wir immer noch vor Röhrenmonitoren, würden das bgcolor-Attribut verwenden und Tabellen-Layouts wie in den späten 1990ern/frühen 2000ern machen. Ach, vergessen Sie das! Wir würden wahrscheinlich immer noch Höhlenwände mit Ockerfarben bemalen.
Außerdem, im Hinblick auf den oben erwähnten feindseligen Kommentar: Andere als Idioten oder Dummköpfe zu bezeichnen – wirklich? Braucht hier jemand Bestätigung für sein Ego?
CSS wird immer weniger intuitiv. Konnte man vor ein paar Jahren die Leute, die sich gut mit CSS auskennen, noch an den Fingern einer, maximal zweier Hände abzählen, kann man jetzt sogar davon ausgehen, dass es eine solche Person gar nicht mehr gibt.
Die Syntax wird furchtbar vermischt. Sagt mir nicht, dass das lesbarer Code ist: https://codepen.io/t_afif/pen/vYweZQa
Ich habe das Gefühl, ich brauche eine kalte Dusche, nachdem ich diesen Artikel gelesen habe. Die Möglichkeiten sind überwältigend. Da geht er hin, mein Schlaf.
Bitte.