So konfigurieren Sie Anwendungsfarbschemata mit benutzerdefinierten CSS-Eigenschaften
Veröffentlicht: 2022-03-10Variablen sind ein grundlegendes Werkzeug, das dabei hilft, Farben in einem Projekt zu organisieren. Lange Zeit verwendeten Front-End-Ingenieure Präprozessorvariablen, um Farben in einem Projekt zu konfigurieren. Aber jetzt bevorzugen viele Entwickler den modernen nativen Mechanismus zum Organisieren von Farbvariablen: CSS Custom Properties. Ihr wichtigster Vorteil gegenüber Präprozessorvariablen besteht darin, dass sie in Echtzeit arbeiten, nicht in der Kompilierungsphase des Projekts, und dass sie das Kaskadenmodell unterstützen, mit dem Sie die Vererbung und Neudefinition von Werten im Handumdrehen verwenden können.
Wenn Sie versuchen, ein Anwendungsfarbschema zu organisieren, können Sie alle benutzerdefinierten Eigenschaften, die sich auf Farbe beziehen, immer im Stammabschnitt platzieren, sie benennen und an allen erforderlichen Stellen verwenden.
Das ist eine Option, aber hilft es Ihnen, Probleme mit dem Anwendungsdesign, White Labeling, einer Markenaktualisierung oder der Organisation eines hellen oder dunklen Modus zu lösen? Was ist, wenn Sie das Farbschema anpassen müssen, um den Kontrast zu erhöhen? Beim aktuellen Ansatz müssen Sie jeden Wert in Ihren Variablen aktualisieren.
In diesem Artikel möchte ich einen flexibleren und widerstandsfähigeren Ansatz zum Aufteilen von Farbvariablen mithilfe benutzerdefinierter Eigenschaften vorschlagen, der viele dieser Probleme lösen kann.
Farbpalette einrichten
Die Farbgebung jeder Website beginnt mit der Einrichtung eines Farbschemas. Ein solches Schema basiert auf dem Farbrad. Normalerweise bilden nur wenige Primärfarben die Grundlage einer Palette, der Rest sind abgeleitete Farben – Töne und Mitteltöne. Meistens ist die Palette statisch und ändert sich nicht, während die Webanwendung ausgeführt wird.
Gemäß der Farbtheorie gibt es nur wenige Möglichkeiten für Farbschemata:
- Monochromatisches Schema (eine Primärfarbe)
- Komplementärschema (zwei Primärfarben)
- Triadenschema (drei Primärfarben)
- Tetradisches Schema (vier Primärfarben)
- Angrenzendes Muster (zwei oder drei Grundfarben)
Für mein Beispiel werde ich mit dem Paletton-Dienst ein Triaden-Farbschema generieren:
Ich habe jetzt drei Hauptfarben. Anhand dieser werde ich die Töne und Mitteltöne berechnen (das HSL-Format in Kombination mit der calc
-Funktion ist dafür ein sehr nützliches Werkzeug). Indem ich den Helligkeitswert ändere, kann ich mehrere zusätzliche Farben für die Palette erzeugen.
Wenn nun die Palette geändert wird, muss nur der Wert der Primärfarben geändert werden. Der Rest wird automatisch neu berechnet.
Wenn Sie HEX- oder RGB-Formate bevorzugen, spielt das keine Rolle; mit den entsprechenden Funktionen des Präprozessors (z. B. mit SCSS und der color-adjust
Funktion) kann bereits beim Kompilieren des Projekts eine Palette gebildet werden. Wie ich bereits erwähnt habe, ist diese Ebene größtenteils statisch; Es kommt äußerst selten vor, dass die Palette in einer laufenden Anwendung geändert wird. Deshalb können wir es mit Präprozessoren berechnen.
Hinweis : Ich empfehle auch, für jede Farbe sowohl HEX-Literal als auch RGB zu generieren. Dies ermöglicht es, in Zukunft mit dem Alphakanal zu spielen.
Die Palettenebene ist die einzige Ebene, auf der die Farbe direkt in den Variablennamen codiert ist, dh wir können die Farbe eindeutig identifizieren, indem wir den Namen lesen.
Definieren Sie Themen- oder Funktionsfarben
Sobald die Palette fertig ist, ist der nächste Schritt die Ebene der funktionalen Farben . Auf dieser Ebene ist der Wert der Farbe nicht so wichtig wie ihr Zweck, die Funktion, die sie erfüllt, und was sie genau einfärbt. Beispielsweise die primäre oder App-Markenfarbe, Rahmenfarbe, Textfarbe auf dunklem Hintergrund, Textfarbe auf hellem Hintergrund, Schaltflächenhintergrundfarbe, Linkfarbe, Hover-Linkfarbe, Hinweistextfarbe und so weiter .
Dies sind äußerst häufige Dinge für fast jede Website oder Anwendung. Wir können sagen, dass solche Farben für ein bestimmtes Farbthema der Anwendung verantwortlich sind. Außerdem werden die Werte solcher Variablen ausschließlich aus der Palette genommen. Daher können wir Anwendungsthemen leicht ändern, indem wir einfach mit verschiedenen Farbpaletten arbeiten.
Unten habe ich drei typische UI-Steuerelemente erstellt: eine Schaltfläche, einen Link und ein Eingabefeld. Sie werden mit Funktionsvariablen eingefärbt, die Werte aus der Palette enthalten, die ich zuvor oben generiert habe. Die Hauptfunktionsvariable, die für das Anwendungsthema (bedingte Marke) verantwortlich ist, ist die primäre Farbvariable.
Mit den drei Schaltflächen oben können Sie die Themen wechseln (die Markenfarbe für Steuerelemente ändern). Die Änderung erfolgt über die entsprechende CSSOM-API (setProperty).
Dieser Ansatz eignet sich nicht nur zum Thematisieren, sondern auch zum Konfigurieren einzelner Webseiten. Auf der Website zubry.by habe ich beispielsweise ein gemeinsames Stylesheet und eine funktionale Variable --page-color
verwendet, um das Logo, die Überschriften, die Steuerelemente und die Textauswahl für alle Seiten einzufärben. Und in den eigenen Stilen jeder Seite habe ich diese Variable einfach neu definiert, um der Seite ihre individuelle Primärfarbe zu setzen.
Komponentenfarben verwenden
Große Webprojekte enthalten immer Dekomposition; Wir zerlegen alles in kleine Bestandteile und verwenden sie an vielen Stellen wieder. Jede Komponente hat normalerweise ihren eigenen Stil, was bedeutet, dass es keine Rolle spielt, was wir zum Zerlegen von BEM- oder CSS-Modulen oder einem anderen Ansatz verwendet haben. Es ist wichtig, dass jeder dieser Codeabschnitte als lokaler Geltungsbereich bezeichnet und wiederverwendet werden kann.
Generell sehe ich in zwei Fällen den Sinn darin, Farbvariablen auf Komponentenebene zu verwenden.
Die erste ist, wenn Komponenten, die gemäß dem Anwendungs-Styleguide mit unterschiedlichen Einstellungen wiederholt werden, z. B. Schaltflächen für unterschiedliche Anforderungen wie primäre (Marken-) Schaltfläche, sekundäre Schaltfläche, tertiäre Schaltfläche und so weiter.
Die zweite ist, wenn Komponenten, die mehrere Zustände mit unterschiedlichen Farben haben, z. B. Button-Hover-, Aktiv- und Fokus-Zustände; normale und ungültige Zustände für Eingabe- oder Auswahlfelder usw.
Ein seltenerer Fall, in dem Komponentenvariablen nützlich sein können, ist die Funktionalität eines „White Labels“. Das „White Label“ ist eine Servicefunktion, die es dem Benutzer ermöglicht, einen Teil der Benutzeroberfläche anzupassen oder mit einem Branding zu versehen, um die Interaktion mit seinen Kunden zu verbessern. Zum Beispiel elektronische Dokumente, die ein Benutzer über einen Dienst oder E-Mail-Vorlagen mit seinen Kunden teilt. In diesem Fall helfen die Variablen auf Komponentenebene dabei, bestimmte Komponenten getrennt vom Rest des Farbthemas der Anwendung zu konfigurieren.
Im folgenden Beispiel habe ich jetzt Steuerelemente zum Anpassen der Farben der primären Schaltfläche (Marke) hinzugefügt. Mithilfe von Farbvariablen auf Komponentenebene können wir UI-Steuerelemente getrennt voneinander konfigurieren.
Wie kann man feststellen, welches Niveau eine Variable hat?
Ich bin auf die Frage gestoßen, wie man versteht, was in die Wurzel (Thema- oder Funktionsebene) eingefügt werden kann und was auf der Ebene einer Komponente belassen werden soll. Dies ist eine ausgezeichnete Frage, die schwer zu beantworten ist, ohne die Situation zu sehen, mit der Sie arbeiten.
Leider funktioniert der gleiche Ansatz wie beim Programmieren nicht mit Farben und Stilen. Wenn wir drei identische Codeteile sehen, müssen wir sie umgestalten.
Farbe kann sich von Bauteil zu Bauteil wiederholen, bedeutet aber nicht, dass es sich dabei um eine Regel handelt. Es kann keine Beziehung zwischen solchen Komponenten geben. Zum Beispiel die Umrandung des Eingabefeldes und der Hintergrund der primären Schaltfläche. Ja, in meinem obigen Beispiel ist das der Fall, aber schauen wir uns das folgende Beispiel an:
Die dunkelgraue Farbe wird wiederholt – dies ist der Rand des Eingabefelds, die Füllfarbe des Schließen-Symbols und der Hintergrund der sekundären Schaltfläche. Aber diese Komponenten sind in keiner Weise miteinander verbunden. Wenn sich die Rahmenfarbe des Eingabefelds ändert, ändern wir den Hintergrund des sekundären Buttons nicht. Für einen solchen Fall müssen wir hier nur die Variable aus der Palette behalten.
Was ist mit Grün? Wir können es höchstwahrscheinlich eindeutig als Primär- oder Markenfarbe definieren. Wenn sich die Farbe der Hauptschaltfläche ändert, ändert sich auch die Farbe des Links und der Kopfzeile der ersten Ebene.
Was ist mit Rot? Ungültige Zustände von Eingabefeldern, Fehlermeldungen und destruktiven Schaltflächen haben auf der gesamten Anwendungsebene dieselbe Farbe. Dies ist ein Muster. Jetzt kann ich mehrere allgemeine Funktionsvariablen im Stammabschnitt definieren:
In Bezug auf die Ebene der Komponentenfarben können wir leicht Komponenten identifizieren, die mithilfe von benutzerdefinierten Eigenschaften angepasst werden können.
Die Schaltfläche wird mit unterschiedlichen Einstellungen wiederholt, die Hintergrundfarbe und der Text für verschiedene Anwendungsfälle ändern sich – primärer, sekundärer, tertiärer, destruktiver oder negativer Fall.
Das Eingabefeld hat zwei Zustände – falsch und normal, wobei sich die Hintergrund- und Rahmenfarben unterscheiden. Setzen wir also diese Einstellungen in Farbvariablen auf der Ebene der entsprechenden Komponenten.
Für die restlichen Komponenten ist es nicht erforderlich, lokale Farbvariablen zu definieren, dies ist redundant.
Sie müssen in die Mustersprache Ihres Projekts eintauchen, die wahrscheinlich vom Designteam und UX entwickelt wird. Ingenieure müssen das gesamte Konzept einer visuellen Sprache vollständig verstehen, nur dann können wir bestimmen, was gemeinsam ist und auf einer funktionalen Ebene leben sollte und was im lokalen Bereich der Sichtbarkeit bleiben sollte.
Aber alles ist nicht so kompliziert, es gibt offensichtliche Dinge. Der allgemeine Hintergrund der Seite, der Hintergrund und die Farbe des Haupttextes bestimmen in den meisten Fällen das Thema Ihrer Anwendung. Es ist äußerst praktisch, solche Dinge zu sammeln, die für die Konfiguration eines bestimmten Modus (wie Dunkel- oder Hellmodus) verantwortlich sind.
Warum nicht alles in den Root-Bereich stellen?
Ich hatte so ein Erlebnis. Beim Lition-Projekt waren das Team und ich mit der Tatsache konfrontiert, dass wir IE11 für die Webanwendung unterstützen mussten, aber nicht für die Website und Landings. Zwischen den Projekten wurde ein gemeinsames UI-Kit verwendet, und wir haben uns entschieden, alle Variablen im Stammverzeichnis zu platzieren, damit wir sie auf jeder Ebene neu definieren können.
Und auch bei diesem Ansatz für die Webanwendung und den IE11-Fall haben wir den Code einfach durch das folgende Postprozessor-Plugin geleitet und diese Variablen in Literale für alle UI-Komponenten im Projekt umgewandelt. Dieser Trick ist nur möglich, wenn alle Variablen im Stammabschnitt definiert wurden, da der Postprozessor die Besonderheiten des Kaskadenmodells nicht verstehen kann.
Jetzt verstehe ich, dass dies nicht der richtige Weg war. Erstens, wenn Sie Komponentenfarben in den Stammbereich einfügen, brechen Sie das Prinzip der Trennung von Anliegen. Als Ergebnis können Sie mit redundantem CSS im Stylesheet enden. Sie haben beispielsweise den Ordner der Komponenten, in dem jede Komponente ihre eigenen Stile hat. Sie haben auch ein gemeinsames Stylesheet, in dem Sie Farbvariablen im Stammabschnitt beschreiben. Sie entscheiden sich, die Schaltflächenkomponente zu entfernen; In diesem Fall müssen Sie daran denken, auch die mit der Schaltfläche verknüpften Variablen aus der gemeinsamen Stildatei zu entfernen.
Zweitens ist dies nicht die beste Lösung in Bezug auf die Leistung. Ja, eine Farbänderung verursacht nur den Vorgang eines Repaints, kein Reflow/Layout, dies ist an sich nicht zu kostspielig, aber wenn Sie einige Änderungen auf höchster Ebene vornehmen, werden Sie mehr Ressourcen verbrauchen, um den gesamten Baum zu überprüfen, als wenn diese Änderungen sind in einem kleinen lokalen Bereich. Ich empfehle, den Leistungsbenchmark von CSS-Variablen von Lisi Linhart für weitere Details zu lesen.
Bei meinem aktuellen Projekt Tispr verwenden das Team und ich Split und dumpen nicht alles im Root, auf der hohen Ebene nur eine Palette und funktionale Farben. Auch vor IE11 haben wir keine Angst, denn dieses Problem wird durch das entsprechende Polyfill gelöst. Installieren Sie einfach das npm-Modul ie11-custom-properties und importieren Sie die Bibliothek in Ihr Anwendungs-JS-Bundle:
// Use ES6 syntax import "ie11-custom-properties"; // or CommonJS require('ie11-custom-properties');
Oder fügen Sie ein Modul nach Skript-Tag hinzu:
<script async src="./node_modules/ie11-custom-properties/ie11CustomProperties.js">
Sie können die Bibliothek auch ohne npm über CDN hinzufügen. Die Arbeit dieser Polyfill basiert auf der Tatsache, dass IE11 nur minimale Unterstützung für benutzerdefinierte Eigenschaften bietet, bei denen Eigenschaften basierend auf der Kaskade definiert und gelesen werden können. Dies ist bei Eigenschaften, die mit doppelten Bindestrichen beginnen, nicht möglich, aber möglicherweise mit einem einzelnen Bindestrich (der Mechanismus ähnelt den Herstellerpräfixen). Sie können mehr darüber in der Repository-Dokumentation lesen und sich mit einigen Einschränkungen vertraut machen. Andere Browser ignorieren diese Polyfüllung.
Nachfolgend finden Sie eine Palette der Tispr-Webanwendung sowie die Steuerelemente der „White Label“-Funktionalität für die E-Dokumente (z. B. Benutzerverträge, Rechnungen oder Angebote).
Warum nicht Farbvariablen auf der JavaScript-Seite speichern?
Eine weitere vernünftige Frage: Warum speichern Sie die Paletten- und Funktionsvariablen nicht im JavaScript-Code? Dies kann auch dynamisch geändert und später durch Inline-Stile neu definiert werden. Dies könnte eine Option sein, aber höchstwahrscheinlich wäre dieser Ansatz weniger optimal, da Sie Zugriff auf bestimmte Elemente haben und ihre Farbeigenschaften ändern müssen. Bei CSS-Variablen ändern Sie nur eine einzige Eigenschaft, nämlich den Variablenwert.
In JavaScript gibt es keine nativen Funktionen oder APIs zum Arbeiten mit Farben. Im CSS-Farbmodul 5 wird es viele Möglichkeiten geben, abgeleitete Farben zu erstellen oder sie irgendwie zu berechnen. Aus der Perspektive der Zukunft sind benutzerdefinierte CSS-Eigenschaften reichhaltiger und flexibler als JS-Variablen. Außerdem gibt es bei JS-Variablen keine Möglichkeit, die Vererbung in Kaskade zu verwenden, und das ist der Hauptnachteil.
Fazit
Die Aufteilung von Farben in drei Ebenen (Palette, Funktion und Komponente) kann Ihnen dabei helfen, sich besser an Änderungen und neue Anforderungen anzupassen, während Sie an einem Projekt arbeiten. Ich glaube, dass benutzerdefinierte CSS-Eigenschaften das richtige Werkzeug sind, um die Farbaufteilung zu organisieren – es spielt keine Rolle, was Sie für das Styling verwenden: reines CSS, Präprozessoren oder CSS-in-JS-Ansatz.
Ich bin durch meine eigene Erfahrung zu diesem Ansatz gekommen, aber ich bin nicht allein. Sara Soueidan beschrieb in ihrem Artikel einen ähnlichen Ansatz, bei dem sie Variablen in globale und Komponentenebenen aufteilte.
Ich möchte auch vorschlagen, den Artikel von Lea Verou zu lesen, in dem sie mögliche Fälle der Anwendung von CSS-Variablen (nicht nur in Bezug auf Farbe) beschreibt.