Les calques Cascade arrivent dans votre navigateur

Les calques Cascade (la règle CSS @layer) seront disponibles dans Chromium 99, Firefox 97 et Safari 15.4 (version bêta). Elles permettent de contrôler plus explicitement vos fichiers CSS afin d'éviter les conflits de spécificité de style. Cela est particulièrement utile pour les grands codebases, les systèmes de conception et la gestion de styles tiers dans des applications.

En superposant votre code CSS de façon claire, vous évitez les remplacements de style inattendus et favorisez une meilleure architecture CSS.

Spécificités CSS et cascade

La spécificité CSS est la manière dont le CSS décide quels styles appliquer à quels éléments. Les différents sélecteurs que vous pouvez utiliser déterminent la spécificité d'une règle de style. Par exemple, les éléments sont moins spécifiques que les classes ou les attributs, qui sont eux-mêmes moins spécifiques que les identifiants. Il s'agit d'un élément essentiel de l'apprentissage des CSS.

Les utilisateurs se tournent vers les conventions d'attribution de noms CSS, telles que BEM, pour éviter d'ignorer involontairement la spécificité. En attribuant à chaque élément un seul nom de classe, tous les éléments sont placés sur le même plan de spécificité. Cependant, il n'est pas toujours possible de conserver un tel style organisé, en particulier lorsque vous travaillez avec du code et des systèmes de conception tiers.

Visuel BEM d'une fiche avec des classes
Exemple de nom utilisé pour BEM sur keepinguptodate.com

Les couches Cascade ont pour but de résoudre ce problème. Elles introduisent une nouvelle couche dans la cascade CSS. Avec les styles superposés, la priorité d'un calque est toujours prioritaire sur la spécificité d'un sélecteur.

Par exemple, le sélecteur .post a.link est plus spécifique que .card a. Si vous essayez de styliser un lien, dans une fiche, dans un post, vous constaterez que le sélecteur le plus spécifique sera appliqué.

En utilisant @layer, vous pouvez être plus explicite sur la spécificité de style de chacun et vous assurer que les styles du lien de la fiche remplacent les styles du lien de l'article, même si la spécificité numérique peut être inférieure si tous vos fichiers CSS se trouvent sur le même plan. Ceci est dû à une priorité en cascade. Les styles multicouches créent de nouveaux "plans" en cascade.

Illustration d'une démonstration de projet montrant comment structurer l'interface utilisateur

@layer en action

Démonstration montrant les couleurs de lien lors des importations
Regardez la démonstration sur Codepen.

Cet exemple présente la puissance des couches de cascade, en utilisant @layer. Plusieurs liens sont affichés: certains sans nom de classe supplémentaire, l'un avec une classe .link et l'autre avec une classe .pink. Le CSS ajoute ensuite trois calques, base, typography et utilities, comme suit :

@layer base {
  a {
    font-weight: 800;
    color: red; /* ignored */
  }

  .link {
    color: blue; /* ignored */
  }
}

@layer typography {
  a {
    color: green; /* styles *all* links */
  }
}

@layer utilities {
  .pink {
    color: hotpink;  /* styles *all* .pink's */
  }
}

Enfin, tous les maillons sont verts ou roses. En effet, bien que .link ait une spécificité de niveau plus élevée que a, il existe un style de couleur pour a dans une priorité @layer plus élevée. a { color: green } remplace .link { color: blue } lorsque la règle verte se trouve dans un calque après la règle bleue.

La priorité des couches l'emporte sur la spécificité de l'élément.

Organiser les calques

Vous pouvez organiser les calques directement sur la page, comme illustré ci-dessus, ou en haut d'un fichier.

L'ordre des calques est établi la première fois que chaque nom de calque apparaît dans votre code.

Cela signifie que si vous ajoutez ce qui suit en haut du fichier, tous les liens apparaîtront en rouge et le lien de la classe .link apparaîtra en bleu:

@layer utilities, typography, base;

En effet, l'ordre des couches est désormais inversé, les utilitaires étant placés en premier et en dernier. Par conséquent, les règles de style du calque base auront toujours une spécificité plus élevée que celles du calque de typographie. Il ne s'agira plus de liens verts, mais de rouge ou de bleu.

Capture d'écran du projet Codepen
Regardez la démonstration sur Codepen.

Organiser les importations

Vous pouvez également utiliser @layer avec des fichiers d'importation. Vous pouvez effectuer cette opération directement lorsque vous importez des styles à l'aide d'une fonction layer(), comme dans l'exemple suivant :

/* Base */
@import '../styles/base/normalize.css' layer(base); /* normalize or rest file */
@import '../styles/base/base.css' layer(base); /* body and base styles */
@import '../styles/base/theme.css' layer(theme); /* theme variables */
@import '../styles/base/typography.css' layer(theme); /* theme typography */
@import '../styles/base/utilities.css' layer(utilities); /* base utilities */

/* Layouts */
@import '../styles/components/post.css' layer(layouts); /* post layout */

/* Components */
@import '../styles/components/cards.css' layer(components); /* imports card */
@import '../styles/components/footer.css' layer(components); /* footer component */

L'extrait de code ci-dessus comporte trois couches: base, layouts et components. Les fichiers de normalisation, de thème et de typographie dans base, avec un fichier post dans layouts, et cards et footer dans components. Lors de l'importation du fichier, les couches sont instanciées à l'aide de la fonction de couche. Une autre approche consiste à organiser vos calques en haut du fichier, en les déclarant avant toute importation:

@layer base,
       theme,
       layouts,
       components,
       utilities;

L'ordre dans lequel vous @import vos styles n'a pas d'importance pour l'ordre du calque, car il est déjà défini à la première occurrence du nom du calque. C’est une chose de moins à vous préoccuper. Vous pouvez toujours définir des fichiers importés pour des calques spécifiques, mais l'ordre est déjà établi.

Capture d'écran de Codepen Project
Découvrez le projet sur Codepen.

Couches et cascade

Prenons du recul et voyons où les couches sont utilisées en lien avec la cascade plus large:

Illustration de la cascade

L'ordre de priorité est le suivant:

  • User-Agent normal (priorité la plus faible)
  • Utilisateur local @layer
  • Utilisateur local (standard)
  • Auteur @layers
  • Normale de l'auteur
  • Auteur !important
  • Auteur @layer !important
  • Utilisateur local !important
  • User-Agent !important** (priorité la plus élevée)

Vous remarquerez peut-être que les styles @layer !important sont inversés. Au lieu d'être moins spécifiques que les styles non superposés (normal), ils ont une priorité plus élevée. Cela est dû à la façon dont !important fonctionne dans la cascade: il rompt la cascade normale dans vos feuilles de style et inverse la spécificité normale au niveau du calque (priorité).

Couches imbriquées

Les calques peuvent également être imbriqués dans d'autres calques. L'exemple suivant provient de l'article Cascade Layers Explainer de Miriam Suzanne:

@layer default {
  p { max-width: 70ch; }
}

@layer framework {
  @layer default {
    p { margin-block: 0.75em; }
  }

  p { margin-bottom: 1em; }
}

Dans l'extrait de code ci-dessus, vous pouvez accéder à framework.default en utilisant un . pour indiquer que la couche default est imbriquée dans framework. Vous pouvez également écrire ceci dans un format plus abrégé:

@layer framework.default {
  p { margin-block: 0.75em }
}

Les couches ainsi que leur ordre sont les suivants:

  • par défaut
  • framework.default
  • framework non superposé
  • sans couche

Points à noter

Les couches Cascade peuvent être intéressantes si vous les utilisez correctement, mais elles peuvent également créer une confusion et des résultats inattendus. Lorsque vous utilisez des couches en cascade, tenez compte des points suivants:

Règle 1: N'utilisez pas @layer pour définir la portée

Les couches Cascade ne permettent pas de résoudre le champ d'application. Si vous disposez d'un fichier CSS avec un élément @layer, dites card.css et que vous souhaitez appliquer un style à tous les liens d'une fiche, ne le écrivez pas comme suit:

a {
  …
}

Ainsi, toutes les balises a de votre fichier obtiendront ce remplacement. Il reste important de définir la portée de vos styles:

.card a {
  …
}

Règle 2: les couches de cascade sont classées derrière un CSS sans couches

Il est important de noter qu'un fichier CSS superposé ne remplace pas le CSS non superposé. Cette décision était intentionnelle, car nous voulions faciliter l'introduction de couches pour travailler plus facilement avec votre codebase existant. L'utilisation d'un fichier reset.css, par exemple, est un bon point de départ et un bon cas d'utilisation pour les couches en cascade.

Règle 3: !important inverse la spécificité en cascade

Bien que les styles superposés soient en général moins spécifiques que les styles non superposés, l'utilisation de !important inverse ce comportement. Dans un calque, les déclarations avec la règle !important sont plus spécifiques que les styles non superposés.

Dans ce cas, les styles !important inversent leur spécificité. Le schéma ci-dessus le montre à titre indicatif: l'auteur @layers a moins de priorité que l'auteur normal, qui ont moins de priorité que l'auteur !important, qui ont moins de priorité que l'auteur @layer !important.

Si vous avez plusieurs calques, le premier calque comportant !important aura la priorité !important et présentera le style le plus spécifique.

Règle 4: Comprendre les points d'injection

Étant donné que l'ordre des calques est établi la première fois que chaque nom de calque apparaît dans votre code, vous pouvez l'ignorer si vous placez une déclaration @layer après l'importation et la définition de layer(), ou après une instruction @layer différente. Contrairement à CSS, où la règle de style située le plus bas sur la page s'applique aux calques en cascade, l'ordre est établi dès la première instance.

Il peut s'agir d'une liste, d'un bloc de calques ou d'une importation. Si vous ajoutez @layer après une liste d'importation avec layer(), cela n'aura aucun effet. En le plaçant en haut du fichier, il définit l'ordre des couches et vous aide à voir clairement les couches au sein de l'architecture.

Règle n° 5: faites attention à votre spécificité

Avec les couches en cascade, un sélecteur moins spécifique (comme a) remplace un sélecteur plus spécifique (comme .link) s'il se trouve sur une couche plus spécifique. Réfléchissez aux points suivants :

a dans layer(components) remplacerait .pink dans layer(utilities) si @layer utilities, components est spécifié. Bien qu'elle fasse partie intentionnelle de l'API, cela peut être déroutant et frustrant si vous ne vous y attendiez pas.

Ainsi, si vous écrivez des classes utilitaires, incluez-les toujours en tant que couche supérieure à celle des composants par lesquels vous souhaitez les remplacer. Vous pourriez vous dire : "Je viens d'ajouter cette classe .pink pour changer la couleur, et elle n'est pas appliquée".

En savoir plus sur les couches de cascade

Vous pouvez également consulter ces ressources pour en savoir plus sur les couches de cascade: