Variables CSS – Pourquoi est-il important de s'y intéresser ?

Les variables CSS, plus précisément appelées "propriétés personnalisées CSS", arrivent dans Chrome 49. Elles peuvent être utiles pour réduire les répétitions dans CSS, ainsi que pour créer des effets d'exécution puissants, tels que le changement de thème et éventuellement l'extension/l'éclosion des futures fonctionnalités CSS.

désencombrement CSS

Lors de la conception d'une application, il est courant de réserver un ensemble de couleurs de marque qui seront réutilisées pour conserver une apparence cohérente. Malheureusement, répéter ces valeurs de couleur encore et encore dans votre code CSS est non seulement une corvée, mais est également source d'erreurs. Si, à un moment donné, l'une des couleurs doit être modifiée, vous pouvez prêter attention au vent et "rechercher et remplacer" toutes les choses, mais sur un projet suffisamment grand, cela pourrait facilement devenir dangereux.

Récemment, de nombreux développeurs se sont tournés vers des préprocesseurs CSS tels que SASS ou LESS, qui résolvent ce problème via l'utilisation de variables de préprocesseur. Bien que ces outils aient considérablement amélioré la productivité des développeurs, les variables qu'ils utilisent présentent un inconvénient majeur : elles sont statiques et ne peuvent pas être modifiées au moment de l'exécution. L'ajout de la possibilité de modifier les variables lors de l'exécution permet non seulement d'ouvrir la porte à des éléments tels que la thématisation dynamique des applications, mais également d'avoir des conséquences majeures pour le responsive design et d'émuler les futures fonctionnalités CSS. Avec le lancement de Chrome 49, ces fonctionnalités sont désormais disponibles sous la forme de propriétés personnalisées CSS.

Propriétés personnalisées en bref

Les propriétés personnalisées ajoutent deux nouvelles fonctionnalités à notre boîte à outils CSS:

  • Possibilité pour un auteur d'attribuer des valeurs arbitraires à une propriété avec un nom choisi par l'auteur.
  • La fonction var(), qui permet à un auteur d'utiliser ces valeurs dans d'autres propriétés.

Voici un bref exemple illustrant

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

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

--main-color est une propriété personnalisée définie par l'auteur avec une valeur #06c. Notez que toutes les propriétés personnalisées commencent par deux tirets.

La fonction var() récupère et se remplace par la valeur de la propriété personnalisée, ce qui génère color: #06c;. Tant que la propriété personnalisée est définie dans la feuille de style, elle doit être disponible pour la fonction var.

La syntaxe peut sembler un peu étrange au premier abord. De nombreux développeurs demandent : "Pourquoi ne pas simplement utiliser $foo pour les noms de variables ?". Cette approche a été spécifiquement choisie pour être aussi flexible que possible et permettre éventuellement l'utilisation de macros $foo à l'avenir. Vous pouvez lire cet article de l'un des auteurs de spécifications, Tab Atkins.

Syntaxe de la propriété personnalisée

La syntaxe d'une propriété personnalisée est simple.

--header-color: #06c;

Notez que les propriétés personnalisées sont sensibles à la casse. Par conséquent, --header-color et --Header-Color sont des propriétés personnalisées différentes. Bien qu'elles puissent sembler simples à première vue, la syntaxe autorisée pour les propriétés personnalisées est en fait assez permissive. Par exemple, la propriété personnalisée suivante est valide:

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

Bien que cette variable ne soit pas utile en tant que variable, car elle ne serait pas valide dans toute propriété normale, elle pourrait potentiellement être lue et utilisée avec JavaScript au moment de l'exécution. Cela signifie que les propriétés personnalisées peuvent exploiter toutes sortes de techniques intéressantes qui ne sont actuellement pas possibles avec les préprocesseurs CSS actuels. Donc, si vous vous dites "bâillements, j'ai une SASS, alors on s'en soucie...", examinez-les de nouveau ! Ce ne sont pas les variables avec lesquelles vous avez l'habitude de travailler.

La cascade

Les propriétés personnalisées suivent les règles de cascade standards. Vous pouvez donc définir la même propriété à différents niveaux de spécificité.

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

Cela signifie que vous pouvez exploiter les propriétés personnalisées dans les requêtes média pour faciliter le responsive design. Un cas d'utilisation peut consister à étendre la marge autour de vos principaux éléments de section à mesure que la taille de l'écran augmente:

:root {
    --gutter: 4px;
}

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

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

Il est important de souligner que l'extrait de code ci-dessus n'est pas possible en utilisant les préprocesseurs CSS actuels, qui ne sont pas en mesure de définir des variables à l'intérieur des requêtes média. Cette capacité ouvre de nombreuses possibilités !

Il est également possible d'avoir des propriétés personnalisées qui tirent leur valeur d'autres propriétés personnalisées. Cela peut être extrêmement utile pour la thématisation:

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

La fonction var()

Pour récupérer et utiliser la valeur d'une propriété personnalisée, vous devez utiliser la fonction var(). La syntaxe de la fonction var() se présente comme suit:

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

<custom-property-name> est le nom d'une propriété personnalisée définie par l'auteur, telle que --foo, et <declaration-value> est une valeur de remplacement à utiliser lorsque la propriété personnalisée référencée n'est pas valide. Les valeurs de remplacement peuvent se présenter sous la forme d'une liste d'éléments séparés par une virgule, qui seront combinées en une seule valeur. Par exemple, var(--font-stack, "Roboto", "Helvetica"); définit une valeur de remplacement de "Roboto", "Helvetica". Gardez à l'esprit que les valeurs abrégées, telles que celles utilisées pour la marge et la marge intérieure, ne sont pas séparées par des virgules. Une valeur de remplacement appropriée pour la marge intérieure ressemblerait donc à ceci.

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

À l'aide de ces valeurs de remplacement, un auteur de composant peut écrire des styles défensifs pour son élément:

/* 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 */
}

Cette technique est particulièrement utile pour thématiser des composants Web qui utilisent Shadow DOM, car les propriétés personnalisées peuvent traverser les limites des ombres. L'auteur d'un composant Web peut créer une conception initiale à l'aide de valeurs de remplacement et exposer des "hooks" de thématisation sous la forme de propriétés personnalisées.

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

Lorsque vous utilisez var(), vous devez faire attention à quelques problèmes. Les variables ne peuvent pas être des noms de propriété. Exemple :

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

Toutefois, cela ne revient pas à définir margin-top: 20px;. Au lieu de cela, la deuxième déclaration n'est pas valide et est considérée comme une erreur.

De même, vous ne pouvez pas (naïvement) créer une valeur lorsqu'une partie de celle-ci est fournie par une variable:

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

Là encore, cela ne revient pas à définir margin-top: 20px;. Pour créer une valeur, vous avez besoin d'autre chose: la fonction calc().

Créer des valeurs avec calc()

Si vous n'avez jamais travaillé avec elle auparavant, la fonction calc() est un petit outil pratique qui vous permet d'effectuer des calculs pour déterminer les valeurs CSS. Elle est compatible avec tous les navigateurs récents et peut être combinée à des propriétés personnalisées pour générer de nouvelles valeurs. Exemple :

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

Utiliser des propriétés personnalisées en JavaScript

Pour obtenir la valeur d'une propriété personnalisée au moment de l'exécution, utilisez la méthode getPropertyValue() de l'objet CSSStyleDeclaration calculé.

/* 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'

De même, pour définir la valeur de la propriété personnalisée au moment de l'exécution, utilisez la méthode setProperty() de l'objet 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');

Vous pouvez également définir la valeur de la propriété personnalisée pour qu'elle fasse référence à une autre propriété personnalisée au moment de l'exécution à l'aide de la fonction var() dans votre appel à 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)');

Étant donné que les propriétés personnalisées peuvent faire référence à d'autres propriétés personnalisées dans vos feuilles de style, vous pouvez imaginer comment cela pourrait entraîner toutes sortes d'effets d'exécution intéressants.

Prise en charge des navigateurs

Actuellement, Chrome 49, Firefox 42, Safari 9.1 et iOS Safari 9.3 sont compatibles avec les propriétés personnalisées.

Démonstration

Testez cet exemple pour avoir un aperçu de toutes les techniques intéressantes que vous pouvez désormais exploiter grâce aux propriétés personnalisées.

Complément d'informations

Si vous souhaitez en savoir plus sur les propriétés personnalisées, Philip Walton de l'équipe Google Analytics a rédigé une présentation expliquant pourquoi il est impatient d'utiliser les propriétés personnalisées. Vous pouvez également suivre leur progression dans d'autres navigateurs sur chromestatus.com.