Im Juli 2020 erhielt ich eine E-Mail von James0x57 (ich versuche immer, Leute mit ihrem Namen zu bezeichnen, aber ich glaube, ich habe das Gefühl, dass sie lieber unter ihrem Benutzernamen bekannt sind), in der steht:
Die gesamte Welt der verzweigten bedingten Logik und des Massen-Feature-Toggling für benutzerdefinierte CSS-Eigenschaften ist möglich und existiert nur wegen einer winzigen Fußnote in der CSS-Spezifikation, die unbemerkt geblieben ist.
Diese Zeile lautet:
Hinweis: Während <declaration-value> mindestens ein Token darstellen muss, kann dieses eine Token ein Leerzeichen sein.
Mit anderen Worten: --foo: ; ist gültig.
Wenn Sie so sind wie ich, liest sich das nicht wie eine massive Offenbarung, die riesige Türen öffnet, aber für klügere Leute, wie James0x57, tut es das! Wir begannen mit der Arbeit an einem Entwurf für einen Blogbeitrag, aber aus verschiedenen Gründen hat er es nicht ganz geschafft. Einer dieser Gründe ist, dass *ich es einfach nicht verstanden habe.* Nennen Sie mich beratungsresistent, Entschuldigung James0x57. Eine Demo, die sie mir schickten, als ich nach einem super vereinfachten Beispiel fragte, war jedoch hilfreich, und ich denke, es hat bei mir irgendwie Klick gemacht. Hier ist meine Interpretation.
Lassen Sie mich versuchen zu erklären
- Der hier eingerichtete Breakpoint ist eine
max-widthMedia Query bei 900px. Sie können sehen, dass die Variable--mq-smvoninitialauf einen leeren Leerzeichenwert wechselt. - Wenn das Browserfenster breiter als 900px ist, ist der Wert von
--mq-sminitial.- Das bewirkt, dass die Variable
--padding-when-smallzwei Werte enthält –initialund2rem–, was, nehme ich an, ungültig ist. - Wenn wir also tatsächlich den Abstand festlegen und diese Variable aufrufen wie
padding: var(--padding-when-small, var(--padding-when-large)), wird der **zweite** Wert (der "Fallback") verwendet, da der erste Wert ungültig ist.
- Das bewirkt, dass die Variable
- Wenn das Browserfenster schmaler als 900px ist, ist der Wert von
--mq-smein Leerzeichen.- Das bewirkt, dass der Wert der Variablen
--padding-when-small"(Leerzeichen)2rem"ist, was, nehme ich an, gültig ist. - Das bedeutet, wenn wir tatsächlich den Abstand festlegen und diese Variable aufrufen wie
padding: var(--padding-when-small, var(--padding-when-large)), wird der **erste** Wert verwendet.
- Das bewirkt, dass der Wert der Variablen
Somit können wir nun den Abstand zwischen zwei Werten umschalten, indem wir eine Platzhaltervariable ändern.
Das ergibt für mich Sinn.
Wenn ich das einfach als Änderung eines einzelnen Wertes sehe, denke ich fast: *Äh, ok, du hast einen wirklich komplexen Weg gefunden, um etwas Abstand zu ändern, aber du hättest den Abstand auch einfach in der Media Query ändern können.* Aber der Trick ist, dass **wir jetzt diese Platzhaltervariable haben, die sich geändert hat, und wir können daran anknüpfen, um unbegrenzt viele andere Werte zu ändern**.
Wir könnten **eine einzige Media Query** (oder eine Reihe von Media Queries) in unserem CSS haben, die nur diese Platzhaltervariablen umschaltet, und wir verwenden sie anderswo, um Werte umzuschalten. Das kann schön und übersichtlich sein, verglichen mit dem Streuen von Media Queries über das gesamte CSS. Es ist ein richtiges Umschalten in CSS, wie eine Form von WENN/DANN-Logik, die wir bisher nicht ganz hatten.
James0x57 hat dieses Denken auf alle logischen Möglichkeiten ausgedehnt, wie UND, ODER, XOR, NAND, NOR und XNOR, aber das hat mich wieder verloren. Ich bin kein Informatiker. *Aber Sie können ihrer Arbeit folgen*, wenn Sie reale Anwendungsfälle dieser Dinge sehen möchten.
Diese Variablensache ist wild und wird sehr verwirrend. Ich habe in einem möglicherweise kürzlichen (aber die Autorenzeile besagt 2015?) *Artikel* von Patrick Brosset bemerkt, der einige knifflige CSS-Custom-Properties behandelt. Zum Beispiel können Fallbacks unendlich verschachtelt sein, wie
color: var(--foo, var(--bar, var(--baz, var(--are, var(--you, var(--crazy)))));
Außerdem können gültige Werte für CSS-Custom-Properties Kommas enthalten, wie dieser
content: var(--foo, one, two, three);
Ist das wirklich nur ein Fallback mit einem einzelnen Wert *one, two, three*? Das ist ziemlich verwirrend.
Nun, schnell einige Monate vorwärts, und die CSS-Trickmeisterin Lea Verou hat *sich dieser Sache angenommen*, nämlich dem Leerzeichen in benutzerdefinierten Eigenschaften
Was wäre, wenn ich Ihnen sagen würde, dass Sie einen einzigen Eigenschaftswert verwenden könnten, um mehrere verschiedene Werte über mehrere verschiedene Eigenschaften und sogar über mehrere CSS-Regeln hinweg ein- und auszuschalten?
Es ist derselbe Trick! In Leas Beispiel nutzt sie jedoch diese Fähigkeit, um
- Variationen für einen Button festzulegen, und
- vier verschiedene Eigenschaften statt einer festzulegen.
Dies verdeutlicht wirklich, warum dieses Konzept so cool ist.
Lea weist auf einige Nachteile hin
Es gibt keine Möglichkeit zu sagen: „Der Hintergrund soll rot sein, wenn
--foogesetzt ist, und ansonsten weiß.“ Einige solcher Bedingungen können durch geschickten Einsatz von Anhängen emuliert werden, aber die meisten nicht.Und natürlich gibt es ein gewisses Lesbarkeitsproblem:
--foo: ;sieht aus wie ein Fehler und--foo: initialsieht ziemlich seltsam aus, es sei denn, man ist sich dieser Technik bewusst.
Wir betreten definitiv die nächste Ära der Verwendung von benutzerdefinierten Eigenschaften. Zuerst haben wir sie wie Preprocessor-Variablen verwendet. Dann sahen wir mehr Kaskaden- und Fallback-Nutzung. Als Nächstes haben wir sie häufiger mit JavaScript verwendet. Jetzt das.
Es gibt noch mehr Artikel darüber, CSS-Preprocessor-Variablen beizubehalten, nicht so sehr für die Fälle, in denen man nur das braucht, was sie können, sondern für die Dinge, die nur sie können, wie die Manipulation ihrer Farbwerte.
Hey, gute Arbeit!
Aber ich kann kein NICHT in reinem CSS für diese Technik finden… UND und ODER sind schön und einfach, aber wie macht man ein NICHT?
Es gibt zwei Möglichkeiten. (Soweit ich das mit dem, was heute verfügbar ist, herausgefunden habe)
Eine Möglichkeit ist, es mit einer pausierten Keyframe-Animation umzuschalten – es ist nicht großartig, aber hier ist eine Demo: https://codepen.io/james0x57/pen/mdExrXy
Die andere Möglichkeit ist, was ich in den meisten css-sweeper-Projekten gemacht habe: Wenn Sie Ihren Anfangszustand festlegen, legen Sie auch eine zweite Variable auf die logische Umkehrung fest. Von dort aus müssen Sie jedes Mal, wenn Sie ein NICHT weiter in der Logik benötigen, das, was Sie tun, auf das NICHT-Bit spiegeln und es mit dem primären Bit mitführen. Im Grunde fälschen Sie es mit 2 Bits, die verschiedene Zustände desselben Bits darstellen – so wie DNA, Quarks, Magnete usw. immer gespiegelte Paare haben. Es steckt viel in diesem Code, aber ich kann keine Zeilen verlinken: https://raw.githubusercontent.com/propjockey/css-sweeper/master/index.html Hier ist ein Screenshot eines solchen Setups: https://i.imgur.com/aho538M.png
So in etwa?
Ok … da die „booleschen“ Werte nie aus einem calc() herauskommen, können Sie NOT-Werte explizit halten. Das verstehe ich.
Die Animations-Technik ist ziemlich interessant!
Danke für deine Antwort!
Wenn Ihr CSS-Minifier
--mq-sm: ;in--mq-sm:;ändert, bricht dieser Trick, oder? Scheint bei mir der Fall zu sein. Ich wäre sehr neugierig, wie konsistent das Verhalten dieser Ausnahmen über verschiedene Browser hinweg implementiert ist und verschiedene Minifier überlebt etc.Ja, Sie müssen defekte Minifier wie CSSNano, das auf PostCSS basiert, vermeiden. In React bedeutet das, dass Sie Ihr CSS manuell in die Datei /public/index.html einfügen müssen: https://create-react-app.dev/docs/using-the-public-folder/
@jon_neal hat einige fantastische Arbeit beim Schreiben von CSS-Parsern geleistet, die dies (und VIELE andere Problembereiche mit PostCSS) korrekt handhaben, also hoffe ich, dass seine Arbeit in dieses Ökosystem Einzug hält.
Es ist ein schöner bekannter Trick, um mit CSS-Variablen zu spielen, auf eine Weise, dass ein Zustand eine Variable auf „unset“ setzt und somit den Fallback-Wert erzwingt. Ich habe damit schon früher experimentiert. CSS hat viele versteckte Überraschungen, man muss nur GRABEN ;)
Ich habe eine Methode erfunden, die der in diesem Artikel ähnelt
Für weitere Details sollten Sie die StackOverflow-Antwort lesen.
(die zweite Methode macht wirklich Spaß)
Das Coole daran ist die Möglichkeit zu wissen, wann eine bestimmte numerische Variable einen bestimmten Zielwert erreicht und dann alles von dort aus zu steuern. Ich habe einen Weg gefunden, eine CSS-Boolesche Variable zu erstellen, die tatsächlich nützlich ist.
Technik angewendet in meinem Pen: https://codepen.io/vsync/pen/mdEJMLv
Ich wollte eine „One-Var-to-Rule-Them-All“-Lösung, also habe ich mir einen netten kleinen Trick ausgedacht, über den ich eigentlich hier schreiben wollte, aber noch nicht dazu gekommen bin, weil ich etwas Tolles in Codepen, für Codepen-Benutzer, baue! Und während ich das tue, habe ich mich dazu hinreißen lassen, noch zwei coole Dinge zu machen…
Wird diese Woche fertig sein.
Sie werden es lieben.
Eine noch einfachere Version: https://codepen.io/CarterLi/pen/xxOWWyX
@carter – es ist vielleicht kürzer, aber es verfehlt den Punkt, dass Sie eine einzige boolesche Variable haben möchten, um mehrere Aspekte Ihres CSS zu steuern, daher benötigen Sie eine tatsächliche einzelne Variable
--booloder wie auch immer Sie sie nennen. Ihr Code beeinflusst nur einfache Dinge (meine Demo auch, aber ich dachte, sie verdeutlicht den Punkt, auf eine Weise, die zeigt, wie die Berechnung einer 0/1-Booleschen Variable in vielen Situationen verwendet werden kann, von denen eine mit Keyframes ist).Stellen Sie sich vor, Sie haben 400 Zeilen CSS und Sie integrieren diese boolesche Variable in viel vom Code, auf viele Arten. Sie möchten keine Keyframes für jede einzelne Situation erstellen. Zuerst versuchen Sie alles, was Sie können, ohne den Keyframes-Hack zu verwenden, und nur, wenn es unmöglich ist – nutzen Sie ihn als letzte Rettung, da er zu viel CSS erzeugt und die globale Umgebung mit benannten Keyframes verschmutzt.
Ich nehme an, dass
--mq-sm: ;eine gültige Aussage ist, weil UNTYPED CSS-Variablen verzögert geparst werden.Ein Wert ist gültig, solange es Zeichen zum Parsen gibt, einschließlich Leerzeichen. Ich denke, untyped CSS-Variablen sind so ziemlich wie Makros in C, sie haben ihre Bedeutung nur, wenn sie irgendwo verwendet werden.
Aber
--mq-sm: initialist eine Ausnahme.--mq-sm: initialverhält sich so, als wäre--mq-smnicht definiert, anstatt den Wertinitialzu haben.Es scheint, dass Browser CSS-Schlüsselwörter
initialunsetinheritbeim Definieren von benutzerdefinierten Eigenschaften erkennen. Die Wahrheit ist, wenninitialnicht erkannt wird, sollte--padding-when-small: var(--mq-sm) 2remals---padding-when-small: initial 2remgeparst werden, währendinitial 2remein perfekt gültiger Wert für CSS-Eigenschaften ist.Ein weiterer Beweis ist, dass, wenn wir
--mq-smetwas anderes alsinitialdefinieren, das Beispiel nicht funktioniert.Die Wahrheit ist also, dass
--mq-sm: initialsich so verhält, als wäre--mq-smnicht definiert, wasvar(--mq-sm)zu einem ungültigen Ausdruck macht. Davar(--mq-sm)ungültig ist, ist--padding-when-small: var(--mq-sm) 2rem;ein ungültiger Ausdruck, was--padding-when-smallundefiniert macht.Daher funktioniert
padding: var(--padding-when-small, var(--padding-when-large));.computedStyleMap und getComputedStyle für Browser ohne Typed CSSOM-Unterstützung sind sehr gute Hilfsmittel für das Debugging von CSS-Eigenschaften.
Noch etwas. Wenn Sie diesen Trick mit Animationen kombinieren würden? Sie könnten sozusagen einen schalterähnlichen Effekt erzeugen, bei dem sich Eigenschaften ändern, je nachdem, welche Zahl einer Eigenschaft zugewiesen ist.
Siehe den Pen Using Space Toggles and Paused/Negative-Delayed Animations to create numerical options von Rock Starwind
(@RockStarwind) auf CodePen.
! ^ Das ist eine Space Toggle-Nutzung der nächsten Stufe. Sie haben im Grunde ein indexierbares Array in reinem CSS erstellt
Jeder, der signifikant fortgeschrittene skriptlose CSS-Spieleprogrammierung (zum Spaß einer Herausforderung) machen möchte, sollte lernen, was @RockStarwind hier erfunden hat!
Es funktioniert nicht mit Firefox. Anscheinend weist FF bei pausierter Animation nie die Anfangswerte zu.
Lea Verou hat vor ein paar Wochen einen Beitrag zu genau diesem Thema veröffentlicht.
https://lea.verou.me/2020/10/the-var-space-hack-to-toggle-multiple-values-with-one-custom-property/
Das tut sie in der Tat, deshalb habe ich sie im Artikel erwähnt und ihre Demo sowie Zitate von ihr aufgenommen.
Hallo Chris Coyier.
Danke für den inspirierenden Artikel.
Sie missverstehen
--foo: initial;.Das Schlüsselwort
initialsetzt auch in diesem Fall die Eigenschaft auf ihren Anfangswert.Das W3C sagt:
Carter Li hat bereits die Auswirkung von
--mq-sm: initial;beschrieben.Ziemlich clever. Aber da dies ein Hack ist, ist er tatsächlich eher verwirrend zu lesen, was in großen Projekten zu einem Albtraum für Debugging/Wartung werden kann. Lesbarkeit sollte die Priorität Nr. 1 in Projekten haben, die auf langfristige Sicht ausgelegt sind. Vielleicht können Pre-/Post-Prozessoren dies auf elegantere Weise nutzen?
Ich bin fasziniert davon, aber ich habe den Artikel mehrmals gelesen und bisher konnte ich mit dem **Space Toggle** keinen Effekt erzielen, den ich nicht bereits einfacher mit **@media queries** erzielen kann.
Am Beispiel des **Paddings** oben, hier ist, was ich mir ausgedacht habe
und… das funktioniert.
Aber es ist genau dasselbe wie das hier
Nun, offensichtlich habe ich etwas verpasst (und es wird zweifellos offensichtlich sein, sobald ich es endlich begriffen habe), aber *was genau* ermöglicht der **Space Toggle**, das nicht nur eine clevere Methode ist, um **@media query**-Werte in Stildeklarationen einzufügen, die *nicht von Media Queries umschlossen sind*?
Wenn Sie etwas suchen, das die Funktionsweise von CSS für immer neu erfinden wird, glaube ich nicht, dass Sie es hier finden werden. Es ist ein (warten Sie darauf) CSS-Trick.
Aber ich finde es *sehr* nett, *mehrere* Eigenschaften festlegen zu können, wenn sich *eine* benutzerdefinierte Eigenschaft ändert. Sicher, das könnte wie eine Media Query sein, aber es könnte auch etwas anderes sein, wie die Tatsache, dass JavaScript es ändert, oder eine
:checked-Zustandsänderung.Es wäre besonders nett, eine Möglichkeit zu haben, dies zu tun, ohne dass es sich wie ein Hack anfühlt.
Mit einer zusätzlichen Variablen können Sie dies tun. Zum Beispiel haben Sie einen
--darkund einen--lightSchalter, bei dem einerinitialund der andere ein Leerzeichen ist. Dann verwenden Siebackground-color: var(--light, white) var(--dark, black);.Einer wird zu seinem Fallback aufgelöst, der andere wird zu einem Leerzeichen aufgelöst und daher ignoriert. Sehen Sie sich den Pen unten an.