CSS-Variablen: Warum ist das wichtig?

CSS-Variablen, genauer gesagt benutzerdefinierte CSS-Properties, werden in Chrome 49 eingeführt. Sie können nützlich sein, um Wiederholungen in CSS zu reduzieren, und auch für leistungsstarke Laufzeiteffekte wie den Themenwechsel und die potenzielle Erweiterung/Polyfillierung zukünftiger CSS-Funktionen.

Unnötige CSS-Codezeilen

Beim Entwerfen einer Anwendung werden häufig eine Reihe von Markenfarben festgelegt, die wiederverwendet werden, um das Erscheinungsbild der App einheitlich zu gestalten. Leider ist es nicht nur mühsam, sondern auch fehleranfällig, diese Farbwerte immer wieder in Ihrem CSS zu wiederholen. Wenn eine der Farben irgendwann geändert werden muss, können Sie alle Elemente mit der Funktion „Suchen und ersetzen“ ändern. Bei einem ausreichend großen Projekt kann dies jedoch schnell gefährlich werden.

In letzter Zeit haben viele Entwickler auf CSS-Preprocessor wie SASS oder LESS umgestellt, die dieses Problem durch die Verwendung von Preprocessor-Variablen lösen. Diese Tools haben die Produktivität der Entwickler zwar enorm gesteigert, die verwendeten Variablen haben jedoch einen großen Nachteil: Sie sind statisch und können nicht zur Laufzeit geändert werden. Die Möglichkeit, Variablen zur Laufzeit zu ändern, eröffnet nicht nur Möglichkeiten für dynamische Anwendungsthemen, sondern hat auch erhebliche Auswirkungen auf responsives Design und das Potenzial, zukünftige CSS-Funktionen zu polyfillen. Mit der Veröffentlichung von Chrome 49 sind diese Funktionen jetzt in Form von benutzerdefinierten CSS-Properties verfügbar.

Benutzerdefinierte Properties – Kurzfassung

Mit benutzerdefinierten Properties werden der CSS-Toolbox zwei neue Funktionen hinzugefügt:

  • Die Möglichkeit für einen Autor, einer Property mit einem vom Autor ausgewählten Namen beliebige Werte zuzuweisen.
  • Die Funktion var(), mit der Autoren diese Werte in anderen Properties verwenden können.

Hier ist ein kurzes Beispiel:

:root {
    --main-color: #06c;
}

#foo h1 {
    color: var(--main-color);
}

--main-color ist eine vom Autor definierte benutzerdefinierte Eigenschaft mit dem Wert #06c. Alle benutzerdefinierten Properties beginnen mit zwei Bindestriche.

Die Funktion var() ruft den Wert der benutzerdefinierten Eigenschaft ab und ersetzt sich damit selbst. Das Ergebnis ist color: #06c;. Solange die benutzerdefinierte Eigenschaft irgendwo in Ihrem Stylesheet definiert ist, sollte sie für die Funktion var verfügbar sein.

Die Syntax mag auf den ersten Blick etwas seltsam aussehen. Viele Entwickler fragen sich: „Warum nicht einfach $foo für Variablennamen verwenden?“ Der Ansatz wurde speziell so gewählt, dass er so flexibel wie möglich ist und in Zukunft möglicherweise $foo-Makros zulässt. Die Hintergrundgeschichte finden Sie in diesem Beitrag von Tab Atkins, einem der Autoren der Spezifikation.

Syntax für benutzerdefinierte Properties

Die Syntax für eine benutzerdefinierte Property ist einfach.

--header-color: #06c;

Bei benutzerdefinierten Properties wird zwischen Groß- und Kleinschreibung unterschieden. --header-color und --Header-Color sind also unterschiedliche benutzerdefinierte Properties. Sie mögen auf den ersten Blick einfach erscheinen, aber die zulässige Syntax für benutzerdefinierte Properties ist tatsächlich recht großzügig. Das folgende Beispiel ist eine gültige benutzerdefinierte Property:

--foo: if(x > 5) this.width = 10;

Dies ist zwar nicht als Variable nützlich, da es in einer normalen Property ungültig wäre, aber es kann bei der Laufzeit mit JavaScript gelesen und verarbeitet werden. Das bedeutet, dass benutzerdefinierte Properties das Potenzial haben, alle möglichen interessanten Techniken zu ermöglichen, die mit den heutigen CSS-Preprocessorn derzeit nicht möglich sind. Wenn Sie also denken: Langweilig, ich habe SASS, also ist das egal…, dann sollten Sie sich das noch einmal genauer ansehen. Das sind nicht die Variablen, mit denen Sie normalerweise arbeiten.

Die Kaskade

Benutzerdefinierte Properties folgen den standardmäßigen Kaskadenregeln. Sie können dieselbe Property also mit unterschiedlicher Spezifität definieren.

:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id="alert">
    While I got red set directly on me!
    <p>I’m red too, because of inheritance!</p>
</div>

Sie können also benutzerdefinierte Properties in Mediaabfragen verwenden, um ein responsives Design zu unterstützen. Ein Anwendungsfall könnte sein, die Ränder um Ihre wichtigsten Abschnittselemente zu vergrößern, wenn die Bildschirmgröße zunimmt:

:root {
    --gutter: 4px;
}

section {
    margin: var(--gutter);
}

@media (min-width: 600px) {
    :root {
    --gutter: 16px;
    }
}

Das obige Code-Snippet ist mit den heutigen CSS-Preprocessorn nicht möglich, da damit keine Variablen in Medienabfragen definiert werden können. Diese Fähigkeit eröffnet viele Möglichkeiten.

Es ist auch möglich, benutzerdefinierte Properties zu haben, deren Wert von anderen benutzerdefinierten Properties abgeleitet wird. Das kann für die Themengestaltung sehr nützlich sein:

:root {
    --primary-color: red;
    --logo-text: var(--primary-color);
}

Die Funktion var()

Wenn Sie den Wert einer benutzerdefinierten Property abrufen und verwenden möchten, müssen Sie die Funktion var() verwenden. Die Syntax der var()-Funktion sieht so aus:

var(<custom-property-name> [, <declaration-value> ]? )

Dabei ist <custom-property-name> der Name einer benutzerdefinierten Property, die vom Ersteller festgelegt wurde, z. B. --foo, und <declaration-value> ist ein Fallback-Wert, der verwendet wird, wenn die referenzierte benutzerdefinierte Property ungültig ist. Fallback-Werte können eine durch Kommas getrennte Liste sein, die zu einem einzelnen Wert kombiniert wird. Beispiel: var(--font-stack, "Roboto", "Helvetica"); definiert einen Fallback von "Roboto", "Helvetica". Kurzzeichen wie die für Ränder und Abstände werden nicht durch Kommas getrennt. Ein geeigneter Fallback für den Abstand würde also so aussehen:

p {
    padding: var(--pad, 10px 15px 20px);
}

Mit diesen Fallback-Werten können Komponentenautoren defensive Stile für ihr Element schreiben:

/* In the component’s style: */
.component .header {
    color: var(--header-color, blue);
}
.component .text {
    color: var(--text-color, black);
}

/* In the larger application’s style: */
.component {
    --text-color: #080;
    /* header-color isn’t set,
        and so remains blue,
        the fallback value */
}

Diese Methode ist besonders nützlich für das Design von Webkomponenten, die das Shadow-DOM verwenden, da benutzerdefinierte Eigenschaften Schattengrenzen überschreiten können. Der Autor einer Webkomponente kann ein erstes Design mithilfe von Fallback-Werten erstellen und Design-„Hooks“ in Form von benutzerdefinierten Eigenschaften freigeben.

<!-- In the web component's definition: -->
<x-foo>
    #shadow
    <style>
        p {
        background-color: var(--text-background, blue);
        }
    </style>
    <p>
        This text has a yellow background because the document styled me! Otherwise it
        would be blue.
    </p>
</x-foo>
/* In the larger application's style: */
x-foo {
    --text-background: yellow;
}

Bei der Verwendung von var() gibt es einige Dinge, die Sie beachten sollten. Variablen dürfen keine Attributnamen sein. Beispiele:

.foo {
    --side: margin-top;
    var(--side): 20px;
}

Dies entspricht jedoch nicht der Einstellung von margin-top: 20px;. Stattdessen ist die zweite Deklaration ungültig und wird als Fehler zurückgegeben.

Ebenso können Sie keinen Wert erstellen, bei dem ein Teil davon von einer Variablen bereitgestellt wird:

.foo {
    --gap: 20;
    margin-top: var(--gap)px;
}

Auch dies entspricht nicht der Einstellung von margin-top: 20px;. Um einen Wert zu erstellen, benötigen Sie noch etwas anderes: die Funktion calc().

Werte mit calc() erstellen

Die Funktion calc() ist ein praktisches Tool, mit dem Sie Berechnungen durchführen können, um CSS-Werte zu ermitteln. Sie wird von allen modernen Browsern unterstützt und kann mit benutzerdefinierten Properties kombiniert werden, um neue Werte zu erstellen. Beispiel:

.foo {
    --gap: 20;
    margin-top: calc(var(--gap) * 1px); /* niiiiice */
}

Mit benutzerdefinierten Properties in JavaScript arbeiten

Um den Wert einer benutzerdefinierten Property zur Laufzeit abzurufen, verwenden Sie die Methode getPropertyValue() des berechneten CSSStyleDeclaration-Objekts.

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>I’m a red paragraph!</p>
/* JS */
var styles = getComputedStyle(document.documentElement);
var value = String(styles.getPropertyValue('--primary-color')).trim();
// value = 'red'

Wenn Sie den Wert eines benutzerdefinierten Attributs zur Laufzeit festlegen möchten, verwenden Sie die Methode setProperty() des CSSStyleDeclaration-Objekts.

/* CSS */
:root {
    --primary-color: red;
}

p {
    color: var(--primary-color);
}
<!-- HTML -->
<p>Now I’m a green paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'green');

Sie können den Wert der benutzerdefinierten Property auch so festlegen, dass er bei der Laufzeit auf eine andere benutzerdefinierte Property verweist. Verwenden Sie dazu die Funktion var() in Ihrem Aufruf von setProperty().

/* CSS */
:root {
    --primary-color: red;
    --secondary-color: blue;
}
<!-- HTML -->
<p>Sweet! I’m a blue paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'var(--secondary-color)');

Da benutzerdefinierte Eigenschaften auf andere benutzerdefinierte Eigenschaften in Ihren Stylesheets verweisen können, können Sie sich vorstellen, dass dies zu allen möglichen interessanten Laufzeiteffekten führen kann.

Unterstützte Browser

Derzeit werden benutzerdefinierte Properties von Chrome 49, Firefox 42, Safari 9.1 und iOS Safari 9.3 unterstützt.

Demo

Im Beispiel sehen Sie, welche interessanten Methoden Sie jetzt dank benutzerdefinierter Properties nutzen können.

Weitere Informationen

Wenn Sie mehr über benutzerdefinierte Properties erfahren möchten, hat Philip Walton vom Google Analytics-Team einen Artikel darüber verfasst, warum er von benutzerdefinierten Properties begeistert ist. Auf chromestatus.com können Sie den Fortschritt der Einführung in anderen Browsern verfolgen.