CSS-Variablen: Warum ist das wichtig?

CSS-Variablen, besser bekannt als benutzerdefinierte CSS-Eigenschaften, sind bald in Chrome 49 verfügbar. Sie können nützlich sein, um Wiederholungen in CSS zu reduzieren und leistungsstarke Runtime-Effekte wie den Designwechsel und die potenzielle Erweiterung/Polyfilling-Funktion zukünftiger CSS-Funktionen einzusetzen.

Durcheinander

Beim Entwerfen einer App ist es üblich, eine Reihe von Markenfarben beiseite zu lassen, die dann wiederverwendet werden, um ein einheitliches Erscheinungsbild der App zu gewährleisten. Leider ist die wiederholte Verwendung dieser Farbwerte in Ihrem CSS nicht nur mühsam, sondern auch fehleranfällig. Muss eine der Farben irgendwann geändert werden, könnten Sie Vorsicht walten lassen und alles „finden und ersetzen“, aber bei einem ausreichend großen Projekt könnte dies gefährlich werden.

In letzter Zeit haben sich viele Entwickler CSS-Präprozessoren wie SASS oder LESS zugewandt, die dieses Problem durch die Verwendung von Präprozessorvariablen 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 während der Laufzeit nicht geändert werden. Wenn Sie Variablen während der Laufzeit ändern können, haben Sie nicht nur die Möglichkeit, dynamische Anwendungsthemen zu erstellen, sondern auch das responsive Design und die Möglichkeit, zukünftige CSS-Funktionen mit Polyfill zu füllen. Mit der Veröffentlichung von Chrome 49 sind diese Funktionen jetzt in Form von benutzerdefinierten CSS-Eigenschaften verfügbar.

Benutzerdefinierte Eigenschaften im Überblick

Mit benutzerdefinierten Eigenschaften werden unserer CSS-Toolbox zwei neue Funktionen hinzugefügt:

  • Möglichkeit für einen Autor, einer Property mit einem vom Autor ausgewählten Namen beliebige Werte zuzuweisen.
  • Die Funktion var(), die es einem Autor ermöglicht, diese Werte in anderen Attributen zu verwenden

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 Eigenschaften beginnen mit zwei Bindestrichen.

Die Funktion var() ruft den Wert der benutzerdefinierten Eigenschaft ab und ersetzt ihn durch diesen Wert, was zu color: #06c; führt. Solange die benutzerdefinierte Eigenschaft an einer Stelle im Stylesheet definiert ist, sollte sie für die Funktion var verfügbar sein.

Die Syntax sieht auf den ersten Blick vielleicht etwas seltsam aus. Viele Entwickler fragen: „Warum verwenden Sie nicht einfach $foo für Variablennamen?“ Der Ansatz wurde ausdrücklich so gewählt, dass er so flexibel wie möglich ist und in Zukunft möglicherweise $foo-Makros zulässt. Informationen zur Hintergrundgeschichte finden Sie in diesem Beitrag des Spezifikationsautors Tab Atkins.

Syntax benutzerdefinierter Eigenschaften

Die Syntax für eine benutzerdefinierte Eigenschaft ist einfach.

--header-color: #06c;

Bei benutzerdefinierten Eigenschaften wird zwischen Groß- und Kleinschreibung unterschieden. --header-color und --Header-Color sind also unterschiedliche benutzerdefinierte Eigenschaften. Auch wenn sie auf den ersten Blick vielleicht einfach erscheinen, ist die zulässige Syntax für benutzerdefinierte Attribute in Wirklichkeit recht großzügig. Das folgende Beispiel zeigt eine gültige benutzerdefinierte Eigenschaft:

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

Diese Variable kann zwar nicht als Variable verwendet werden, wäre aber in allen normalen Properties ungültig. Sie könnte aber möglicherweise während der Laufzeit mit JavaScript gelesen und verarbeitet werden. Mit benutzerdefinierten Attributen können also alle möglichen interessanten Techniken genutzt werden, die mit den heutigen CSS-Präprozessoren nicht möglich sind. Wenn du also denkst: „Gähnen, ich habe SASS, wem kümmert es...“, dann sieh dir das Ganze noch einmal an. Das sind nicht die Variablen, mit denen Sie vertraut sind.

Der Wasserfall

Benutzerdefinierte Eigenschaften folgen den standardmäßigen Kaskadenregeln, sodass Sie dieselbe Eigenschaft mit unterschiedlichen Spezifitätsstufen definieren können

: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>

Das bedeutet, dass Sie benutzerdefinierte Eigenschaften in Medienabfragen nutzen können, um das responsive Design zu unterstützen. Ein Anwendungsfall könnte sein, den Rand um die Hauptelemente zu vergrößern, wenn der Bildschirm größer wird:

:root {
    --gutter: 4px;
}

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

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

Beachten Sie, dass das obige Code-Snippet mit den heutigen CSS-Präprozessoren, die keine Variablen innerhalb von Medienabfragen definieren können, nicht möglich ist. Diese Fähigkeit eröffnet Ihnen viel Potenzial.

Es ist auch möglich, benutzerdefinierte Eigenschaften zu haben, deren Wert von anderen benutzerdefinierten Eigenschaften abgeleitet wird. Dies kann für die Themengestaltung äußerst nützlich sein:

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

Die Funktion var()

Um den Wert einer benutzerdefinierten Eigenschaft abzurufen und zu verwenden, müssen Sie die Funktion var() verwenden. Die Syntax für die var()-Funktion sieht so aus:

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

Dabei ist <custom-property-name> der Name einer vom Autor definierten benutzerdefinierten Eigenschaft, z. B. --foo, und <declaration-value> ist ein Fallback-Wert, der verwendet wird, wenn das benutzerdefinierte Attribut, auf das verwiesen wird, ungültig ist. Fallback-Werte können eine durch Kommas getrennte Liste sein, die zu einem einzelnen Wert kombiniert wird. var(--font-stack, "Roboto", "Helvetica"); definiert beispielsweise als Fallback "Roboto", "Helvetica". Denken Sie daran, dass Kurzwerte, wie sie für den Rand und das Auffüllen verwendet werden, nicht durch Kommas getrennt sind, sodass eine geeignete Alternative für das Auffüllen so aussehen würde.

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

Mit diesen Fallback-Werten kann ein Komponentenautor Defensivstile für sein 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 Technik ist besonders nützlich, um Webkomponenten mit Shadow-DOM als Themen zu definieren, da benutzerdefinierte Eigenschaften Schattengrenzen durchlaufen können. Ein Webkomponenten-Autor kann ein ursprüngliches Design mit Fallback-Werten erstellen und diese „Hooks“ in Form von benutzerdefinierten Attributen zur Verfügung stellen.

<!-- 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;
}

Wenn du var() verwendest, gibt es ein paar Dinge, auf die du achten solltest. Variablen können 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 ausgegeben.

Ebenso können Sie (naiv) keinen Wert aufbauen, bei dem ein Teil davon durch eine Variable bereitgestellt wird:

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

Auch dies entspricht nicht der Einstellung margin-top: 20px;. Zum Erstellen eines Werts benötigen Sie etwas anderes: die Funktion calc().

Werte mit calc() erstellen

Wenn Sie noch nie damit gearbeitet haben, ist die calc()-Funktion ein kleines Tool, mit dem Sie Berechnungen zur Bestimmung von CSS-Werten durchführen können. Es wird von allen modernen Browsern unterstützt und kann mit benutzerdefinierten Eigenschaften kombiniert werden, um neue Werte zu erstellen. Beispiel:

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

Benutzerdefinierte Eigenschaften in JavaScript verwenden

Verwenden Sie die Methode getPropertyValue() des berechneten CSSStyleDeclaration-Objekts, um den Wert einer benutzerdefinierten Eigenschaft zur Laufzeit abzurufen.

/* 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 der benutzerdefinierten Eigenschaft zur Laufzeit festlegen möchten, verwenden Sie die Methode setProperty() des Objekts CSSStyleDeclaration.

/* 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 auch festlegen, dass der Wert der benutzerdefinierten Eigenschaft zur Laufzeit auf eine andere benutzerdefinierte Eigenschaft verweist. Verwenden Sie dazu die Funktion var() in Ihrem setProperty()-Aufruf.

/* 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 in Ihren Stylesheets auf andere benutzerdefinierte Eigenschaften verweisen können, könnte dies zu den verschiedensten interessanten Laufzeiteffekten führen.

Unterstützte Browser

Derzeit unterstützen Chrome 49, Firefox 42, Safari 9.1 und iOS Safari 9.3 benutzerdefinierte Eigenschaften.

Demo

Sie können dieses Beispiel ausprobieren, um einen Einblick in alle interessanten Techniken zu erhalten, die Sie jetzt dank benutzerdefinierter Eigenschaften nutzen können.

Weitere Informationen

Falls Sie mehr über benutzerdefinierte Properties erfahren möchten, hat Philip Walton vom Google Analytics-Team einen Leitfaden verfasst, in dem erläutert wird, warum er sich für benutzerdefinierte Properties begeistert. Den Fortschritt in anderen Browsern können Sie auch auf chromestatus.com verfolgen.