Les calques Cascade arrivent dans votre navigateur

Les calques en cascade (la règle CSS @layer) seront disponibles dans Chromium 99, Firefox 97 et Safari 15.4 Bêta. Ils 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 des styles tiers dans les applications.

En stratifiant votre CSS de manière claire, vous évitez les remplacements de style inattendus et améliorez l'architecture CSS.

Spécificité CSS et cascade

La spécificité CSS permet au CSS de déterminer les styles à appliquer aux éléments. Les différents sélecteurs que vous pouvez utiliser déterminent la spécificité de chaque règle de style. Par exemple, les éléments sont moins spécifiques que les classes ou les attributs, qui sont à leur tour moins spécifiques que les ID. Il s'agit d'une partie essentielle de l'apprentissage du CSS.

Les concepteurs se tournent vers des conventions d'attribution de noms CSS telles que BEM pour éviter de remplacer la spécificité par inadvertance. En attribuant un seul nom de classe à tous les éléments, vous les placez tous sur le même plan de spécificité. Cependant, il n'est pas toujours possible de maintenir des styles aussi organisés, en particulier lorsque vous travaillez avec du code et des systèmes de conception tiers.

Illustration BEM d'une fiche avec des classes
Exemple illustré de dénomination BEM de keepinguptodate.com.

Les couches en cascade visent à résoudre ce problème. Ils introduisent une nouvelle couche dans la cascade CSS. Avec les styles en couches, la priorité d'une couche l'emporte toujours 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 d'un post, 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 de votre lien de carte remplacent les styles de votre lien de post, même si la spécificité peut être numériquement inférieure si tous vos CSS se trouvent sur le même plan. Cela est dû à la priorité en cascade. Les styles en couches créent de nouveaux "plans" en cascade.

Illustration de la démonstration du projet de décomposition de l'UI

@layer en action

Démo montrant les couleurs des liens avec les importations
Voir la démonstration sur Codepen

Cet exemple illustre la puissance des calques en cascade à l'aide de @layer. Plusieurs liens s'affichent: certains sans nom de classe supplémentaire, un avec une classe .link et un avec une classe .pink. Le CSS ajoute ensuite trois couches: 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 */
  }
}

À terme, tous les liens sont verts ou roses. En effet, bien que .link ait une spécificité au niveau du sélecteur plus élevée que a, il existe un style de couleur sur a dans un @layer de priorité supérieure. 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 calques l'emporte sur la spécificité des éléments.

Organiser les calques

Vous pouvez organiser les calques directement sur la page, comme indiqué 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, les liens s'afficheront tous en rouge, et le lien de la classe .link en bleu:

@layer utilities, typography, base;

En effet, l'ordre des calques est désormais inversé, les éléments utilitaires étant placés en premier et la base en dernier. Par conséquent, les règles de style de la couche base auront toujours une spécificité plus élevée que les règles de style de la couche de typographie. Ils ne seront plus verts, mais rouges ou bleus.

Capture d'écran du projet Codepen
Voir la démonstration sur Codepen

Organiser les importations

Vous pouvez également utiliser @layer avec des fichiers d'importation. Vous pouvez le faire 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 calques sont instanciés à l'aide de la fonction de calque. Vous pouvez également organiser vos calques en haut du fichier, en les déclarant avant toute importation:

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

Désormais, l'ordre dans lequel vous @import vos styles n'a plus d'importance pour l'ordre des calques, car il est déjà établi à la première occurrence du nom du calque. Un souci de moins. Vous pouvez toujours définir des fichiers importés sur des calques spécifiques, mais l'ordre est déjà établi.

Capture d'écran du projet Codepen
Explorez le projet sur Codepen.

Couches et cascade

Prenons un peu de recul et voyons où les couches sont utilisées par rapport à la cascade plus large:

Illustration de cascade

L'ordre de priorité est le suivant:

  • User-agent normal (priorité la plus faible)
  • Utilisateur local @couche
  • Utilisateur local normal
  • Auteur @layers
  • Auteur normal
  • Auteur !important
  • Auteur @layer !important
  • Utilisateur local !important
  • User-agent !important** (priorité la plus élevée)

Vous remarquerez ici que les styles @layer !important sont inversés. Au lieu d'être moins spécifiques que les styles non superposés (normaux), ils ont une priorité plus élevée. Cela s'explique par le fonctionnement de !important dans la cascade: il interrompt la cascade normale dans vos feuilles de style et inverse la spécificité normale au niveau de la couche (préséance).

Calques imbriqués

Les calques peuvent également être imbriqués dans d'autres calques. L'exemple suivant provient de la présentation des calques en cascade 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 à l'aide d'un . pour indiquer que la couche default est imbriquée dans framework. Vous pouvez également écrire cela de manière plus abrégée:

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

Les calques et l'ordre des calques obtenus sont les suivants:

  • par défaut
  • framework.default
  • framework sans calque
  • sans superposition

Points à noter

Les calques en cascade peuvent être très utiles si vous les utilisez correctement, mais ils peuvent aussi créer de la confusion et des résultats inattendus. Tenez compte des points suivants lorsque vous utilisez des calques en cascade:

Règle 1: N'utilisez pas @layer pour définir le champ d'application

Les calques en cascade ne résolvent pas le problème de champ d'application. Si vous disposez d'un fichier CSS avec un @layer, par exemple card.css, et que vous souhaitez styliser tous les liens de la fiche, n'écrivez pas de styles comme:

a {
  
}

Toutes les balises a de votre fichier recevront ce forçage. Il est néanmoins important de définir correctement la portée de vos styles:

.card a {
  
}

Règle 2: les couches en cascade sont triées derrière les CSS non stratifiés

Notez qu'un fichier CSS en couches ne remplace pas le CSS non en couches. Il s'agit d'une décision délibérée visant à faciliter l'introduction de calques de manière plus judicieuse pour travailler avec votre codebase existant. L'utilisation d'un fichier reset.css, par exemple, constitue un bon point de départ et un bon cas d'utilisation pour les calques en cascade.

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

Bien que les styles en couches soient généralement moins spécifiques que les styles sans couches, l'utilisation de !important inverse cette tendance. Dans une couche, les déclarations avec la règle !important sont plus spécifiques que les styles sans couche.

Dans ce cas, les styles !important inversent leur spécificité. Le diagramme ci-dessus le montre à titre de référence: les attributs author @layers ont moins de priorité que les attributs author normal, qui ont moins de priorité que les attributs author !important, qui ont moins de priorité que les attributs author @layer !important.

Si vous avez plusieurs calques, le premier calque avec !important sera prioritaire et sera le style le plus spécifique.!important

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, si vous placez une déclaration @layer après avoir importé et défini des layer(), ou après une autre instruction @layer, elle peut être ignorée. Contrairement au CSS, où la règle de style la plus basse de la page est appliquée pour les couches en cascade, l'ordre est établi à la première instance.

Il peut s'agir d'une liste, d'un bloc de calques ou d'une importation. Si vous placez @layer après une liste d'importation avec layer(), rien ne se passe. En le plaçant en haut du fichier, vous définirez l'ordre des calques et vous pourrez voir clairement les calques dans l'architecture.

Règle 5: Faites attention à votre niveau de spécificité

Avec les calques en cascade, un sélecteur moins spécifique (comme a) remplace un sélecteur plus spécifique (comme .link) si ce sélecteur moins spécifique se trouve sur un calque plus spécifique. Réfléchissez aux éléments suivants :

a dans layer(components) remplace .pink dans layer(utilities) si: @layer utilities, components a été spécifié. Bien que cela soit intentionnel dans l'API, cela peut être déroutant et frustrant si vous ne vous y attendez pas.

Par conséquent, si vous écrivez des classes utilitaires, incluez-les toujours en tant que couche de niveau supérieur que les composants que vous prévoyez de remplacer. Vous pourriez penser : "Je viens d'ajouter cette classe .pink pour modifier la couleur, mais elle n'est pas appliquée."

En savoir plus sur les calques en cascade

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