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, sont disponibles dans Chrome 49. Ils peuvent être utiles pour réduire les répétitions dans CSS, mais aussi pour des effets d'exécution puissants tels que le changement de thème et potentiellement l'extension ou le polyfill de futures fonctionnalités CSS.

Encombrement CSS

Lors de la conception d'une application, il est courant de mettre de côté un ensemble de couleurs de marque qui seront réutilisées pour assurer la cohérence de l'apparence de l'application. Malheureusement, le fait de répéter encore et encore ces valeurs de couleur dans votre code CSS est non seulement une corvée, mais aussi une source d'erreurs. Si, à un moment donné, l'une des couleurs doit être modifiée, vous pouvez faire preuve de prudence et mettre en garde contre le vent et "trouver et remplacer" toutes les choses, mais sur un projet suffisamment vaste, 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 grâce à 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 : ils sont statiques et ne peuvent pas être modifiés au moment de l'exécution. La possibilité de modifier des variables au moment de l'exécution ouvre la voie à des éléments tels que la thématisation d'application dynamique, mais elle a également des conséquences majeures pour le responsive design et la possibilité de polyfill de futures fonctionnalités CSS. Avec le lancement de Chrome 49, ces fonctionnalités sont désormais disponibles sous la forme de propriétés CSS personnalisées.

Propriétés personnalisées en résumé

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 exemple rapide pour illustrer

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

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

--main-color est une propriété personnalisée définie par l'auteur, avec la 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 votre 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 se demandent : "Pourquoi ne pas simplement utiliser $foo pour les noms de variables ?" L'approche a été choisie spécifiquement pour être aussi flexible que possible et permettre éventuellement l'utilisation de macros $foo à l'avenir. Pour en savoir plus, consultez ce post de l'un des auteurs de la spécification, Tab Atkins.

Syntaxe des propriétés personnalisées

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. --header-color et --Header-Color sont donc 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. Voici un exemple de propriété personnalisée 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 éventuellement être lue et traité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âillement, j'ai Bâillements, alors ça s'ennuie...", regardez à nouveau. Ce ne sont pas les variables que vous avez l'habitude d'utiliser.

La Cascade

Les propriétés personnalisées suivent les règles standards de cascade d'annonces. 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 des propriétés personnalisées dans les requêtes multimédias pour faciliter le responsive design. Un cas d&#39;utilisation peut être d&#39;élargir les marges autour de vos principaux éléments de sectionnement à mesure que la taille de l&#39;écran augmente:

:root {
    --gutter: 4px;
}

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

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

Il est important de noter que l&#39;extrait de code ci-dessus n&#39;est pas possible avec les préprocesseurs CSS actuels, qui ne peuvent pas définir de variables dans les requêtes multimédias. Cette capacité ouvre de nombreuses possibilités.

Il est également possible d'utiliser 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, comme --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 être des listes séparées par une virgule, qui seront combinées en une seule valeur. Par exemple, var(--font-stack, "Roboto", "Helvetica"); définit une valeur de remplacement pour "Roboto", "Helvetica". Gardez à l'esprit que les valeurs abrégées, comme celles utilisées pour la marge et la marge intérieure, ne sont pas séparées par une virgule. Une solution de remplacement appropriée pour la marge intérieure ressemblerait donc à ceci.

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

À l&#39;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 les composants Web qui utilisent Shadow DOM, car les propriétés personnalisées peuvent traverser les limites d&#39;ombre. Un auteur de composants Web peut créer une conception initiale à l&#39;aide de valeurs de remplacement et exposer des &quot;hooks&quot; 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 erreurs. Les variables ne peuvent pas être des noms de propriétés. Par exemple :

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

Toutefois, cela n'équivaut pas à définir margin-top: 20px;. À la place, la deuxième déclaration n&#39;est pas valide et est rejetée en tant qu&#39;erreur.

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

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

Encore une fois, cela n'équivaut pas à définir margin-top: 20px;. Pour créer une valeur, vous avez besoin d'un autre élément: 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. Il est compatible avec tous les navigateurs modernes et peut être combiné à des propriétés personnalisées pour créer 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 faire référence à une autre propriété personnalisée au moment de l'exécution en utilisant 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 acceptent les propriétés personnalisées.

Démo

Essayez l'exemple pour découvrir toutes les techniques intéressantes que vous pouvez désormais exploiter grâce aux propriétés personnalisées.

Documentation complémentaire

Pour en savoir plus sur les propriétés personnalisées, Philip Walton de l'équipe Google Analytics a rédigé un article expliquant pourquoi il est enthousiaste à l'égard des propriétés personnalisées. Vous pouvez également suivre leur progression dans d'autres navigateurs sur chromestatus.com.