Modul-Blog


Das Web verstehen. Ein Blick hinter die Kulissen.

CSS Schema Switcher
Spaß und Profit mit Custom Properties


Die Gestaltungselemente einer Webseite mittels CSS zu klassifizieren und zu formatieren ist nicht nur die Basis einer wartbaren Internetseite, sondern auch Grundvoraussetzung für die Implementierung verschiedener Themata (engl. “Themes”).

Schließlich bildet der zentrale und vom Inhalt abgekoppelte Charakter der Style-Definition nun mal den idealen Ansatzpunkt um Formatbeschreibungen einfach und bequem austauschen zu können. Wurde ein gutes Namenskonzept gewählt und die Selektoren konsequent appliziert, entfaltet sich die volle Stärke von CSS, wirken sich Änderungen doch über Kaskaden hinweg auf die zugrundeliegenden HTML-Elemente im DOM aus.

Sind alle Klassen definiert und an den Elementen verankert, so genügt eine Änderung am Stylesheet und ein Neuladen der Seite um die getätigten Änderungen auf die Darstellung anzuwenden. Was aber, wenn sie einen kompletten Satz an Klassifizierungen ohne Neuzuladen direkt im Browser ändern möchten, weil Sie z.B. zwischen zwei Themes oder verschiedenen Farbschemata wechseln möchten? Dann könnte der in diesem Artikel beschriebene Ansatz für Sie interessant sein.

CSS Switching Scheme

Die Basis

Grundlage des hier geschilderten Mechanismus bieten CSS-Variablen und das JavaScript-Objekt CSSStyleDeclaration bzw. dessen Methoden getPropertyValue() und setProperty().

Definieren wir zunächst den sogenannten Basisbereich mit einigen Kernvariablen für die einzusetzenden Formatierungen:

:root {
  --font-main: 'Roboto Condensed', sans-serif;
  --bg-light: #f7d6e6;
  --bg-dark: #de5c9d;
  --text-light: #fff;
  --text-dark: #444;
  --text-highlight: #d63384;
  --brand-icon: url("../img/brand-icon.png");
}  

Endgültige Semantik erhalten diese jedoch erst durch die Adressierung innerhalb der vom Designer vorgesehenen Klassenselektoren:

body {
  font-family: var(--font-main);
}

.bg-dark {
  background: var(--bg-dark);
}

.bg-light {
  background: var(--bg-light);
}

.text-light {
  color: var(--text-light);
}

.text-dark {
  color: var(--text-dark);
}

.text-highlight {
  color: var(--text-highlight);
}

img.brand-icon {
  content: var(--brand-icon);
}

Das zugehörige HTML könnte so aussehen:

<html>
  <head>
    <!-- ... -->
  </head>
  <body>
    <header>
      <img src="/img/dummy.png" title="Brand icon" class="brand-icon" />
      Example app
    </header>
    <main>
      <section class="bg-dark">
        <div class="text-light">
          Lorem ipsum dolor sit amet.
        </div>
      </section>
      <section class="bg-light">
        <div class="text-dark">
          Lorem ipsum dolor <span class="text-highlight">sit</span> amet.
        </div>
      </section>      
    </main>
  </body>
</html>

Bis hierhin ist alles keine große Magie und wir bewegen uns in gewohntem Terrain: CSS-Klassendefinition + Zuweisung im HTML-Dokument.

Hot-Reloading

Kommen wir nun aber zum eingangs postulierten Wunsch der Live-Änderung von designierten Theming-Schemata. Dies kann bewerkstelligt werden, indem zunächst verschiedene Varianten der bereits definierten Kernvariablen deklariert werden.

Den Name leitet man idealerweise aus dem der zugehörigen Kernvariable ab und konkateniert als Suffix beispielsweise einen Zahlenwert. So ergibt sich für zwei Schemata z.B.:

:root {

  /* variation 1 */
  --font-main-1: 'Roboto Condensed', sans-serif;
  --bg-light-1: #f7d6e6;
  --bg-dark-1: #de5c9d;
  --text-light-1: #fff;
  --text-dark-1: #444;
  --text-highlight-1: #d63384;
  --brand-icon-1: url("../img/brand-icon.png");

  /* variation 2 */
  --font-main-2: 'Fira Sans Condensed', sans-serif;
  --bg-light-2: #fff;
  --bg-dark-2: #e3f6f5;
  --text-light-2: #777;
  --text-dark-2: #444;
  --text-highlight-2: #7bd3d3; 
  --brand-icon-2: url("../img/brand-icon2.png");

  /* ... */

}

Diese kann man nun im bereits definierten Basisbereich referenzieren. Standardmäßig verwenden wir das Schema 1, weisen also die Variablen mit dem 1er-Suffix zu:

:root {

  /* ... */

  --font-main: var(--font-main-1);
  --bg-light: var(--bg-light-1);
  --bg-dark: var(--bg-dark-1);
  --text-light: var(--text-light-1);
  --text-dark: var(--text-dark-1);  
  --text-highlight: var(--text-highlight-1);
  --brand-icon: var(--brand-icon-1);

}

Unsere HTML-Elemente sind bereits mit den Kernvariablen gekoppelt. Folglich führt eine Änderung dieser Variablen auch zu einer Änderung der Darstellung. Es muss uns jetzt nur noch gelingen, einen Schema-Wechsel derart zu implementieren, dass sämtliche dem Schema inhärenten Variablen lückenlos in die Kernvariablen überführt werden, wollten wir beispielsweise einen Wechsel zu Schema 2 vollziehen. Der folgende JavaScript-Code leistet dies:

var classes = [
  "font-main",
  "bg-light",
  "bg-dark",  
  "text-light",
  "text-dark",
  "text-highlight",
  "brand-icon"
];             

function switchScheme(no) {
  for (var i in classes) {
    var clz = classes[i];
    var value = style.getPropertyValue("--" + clz + "-" + no);
    if (value !== "") {
      root.style.setProperty(
        "--" + clz, 
        value
      );
    }
  }	
}

Wir definieren unsere verwendeten Klassen als Array, traversieren diesen und wenden dann die Ersetzungslogik an. Hierfür wird aus der Klasse der aktuellen Iteration der Klassename im Kontext des spezifizierten Schemas (Funktionsparameter no) gebildet. Zusätzlich erfolgt ein Lookup via style.getPropertyValue() mit diesem Schlüssel, sodass anschließend der Wert der gesuchten Eigenschaft zur Verfügung steht. Jener kann schlußendlich mittels style.setPropertyValue() der passenden Kernvariable zugewiesen werden. Das Rerendering der Darstellung erfolgt umgehend 🚀🚀🚀.

Fazit

Das im Artikel beschriebene Vorgehen eignet sich hervorragend um einen Theming-Konfigurator zu implementieren. So macht auch der Konfigurator der Modulseiten KLEIN hiervon Gebrauch. Hier werden zusätzlich zu Vorlagen und Modulen auch Schemata verwendet und mithilfe der o.g. Strategie wechselbar gestaltet. Der Schema-Wechsel kann anschaulich im Konfigurator getestet werden (1, 2, 3).

28.3.2022

692 Wörter

Kategorien
Tags
CSS HTML JavaScript