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.
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.
@layer
en action
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.
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.
Couches et cascade
Prenons du recul et voyons où les couches sont utilisées en lien avec la cascade plus large:
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: