@scope
La règle @ CSS @scope
permet de sélectionner des éléments dans des sous-arbres spécifiques du DOM, en ciblant précisément les éléments sans écrire des sélecteurs trop spécifiques difficiles à surcharger, et sans lier vos sélecteurs de façon trop étroite à la structure du DOM.
En JavaScript, @scope
est accessible via l'interface du modèle d'objet CSS CSSScopeRule
.
Syntaxe
La règle @scope
contient un ou plusieurs ensembles de règles (appelées règles de style portées) et définit une portée dans laquelle les appliquer aux éléments sélectionnés. @scope
peut être utilisée de deux façons :
-
Comme bloc autonome dans votre CSS, auquel cas elle inclut une section de prélude contenant les sélecteurs de racine de portée et éventuellement de limite de portée — ceux-ci définissent les bornes supérieure et inférieure de la portée.
css@scope (scope root) to (scope limit) { /* … */ }
-
Comme styles en ligne inclus dans un élément
<style>
de votre HTML, auquel cas le prélude est omis et l'ensemble de règles inclus est automatiquement porté sur l'élément parent englobant du<style>
.html<parent-element> <style> @scope { /* règles */ } </style> </parent-element>
Il est aussi possible de combiner un
@scope
en ligne avec un sélecteur de limite de portée, comme dans@scope to (scope limit) { ... }
.
Description
Un document web complexe peut inclure des composants tels que des en-têtes, pieds de page, articles d'actualité, cartes, lecteurs multimédias, publicités, etc. Lorsque la complexité augmente, la gestion efficace du style de ces composants devient un enjeu, et le bon usage de la portée des styles aide à gérer cette complexité. Considérons l'arbre DOM suivant :
body └─ article.feature ├─ section.article-hero │ ├─ h2 │ └─ img │ ├─ section.article-body │ ├─ h3 │ ├─ p │ ├─ img │ ├─ p │ └─ figure │ ├─ img │ └─ figcaption │ └─ footer ├─ p └─ img
Si vous souhaitez sélectionner l'élément <img>
à l'intérieur d'une <section>
ayant la classe article-body
, vous pouvez procéder ainsi :
- Écrire un sélecteur comme
.feature > .article-body > img
. Cependant, celui-ci a une spécificité élevée et est donc difficile à surcharger, et il est aussi fortement lié à la structure du DOM. Si votre structure HTML change à l'avenir, vous devrez peut-être réécrire votre CSS. - Écrire quelque chose de moins spécifique comme
.article-body img
. Cependant, cela sélectionnera toutes les images à l'intérieur de lasection
.
C'est là que @scope
est utile. Elle permet de définir une portée précise dans laquelle vos sélecteurs peuvent cibler des éléments. Par exemple, vous pouvez résoudre le problème ci-dessus avec un bloc autonome @scope
comme suit :
@scope (.article-body) to (figure) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
Le sélecteur de racine de portée .article-body
définit la borne supérieure de la portée de l'arbre DOM dans laquelle l'ensemble de règles sera appliqué, et le sélecteur de limite de portée figure
définit la borne inférieure. Ainsi, seuls les éléments <img>
à l'intérieur d'une <section>
avec la classe article-body
, mais pas à l'intérieur d'un élément <figure>
, seront sélectionnés.
Note : Ce type de portée — avec une borne supérieure et une borne inférieure — est couramment appelé portée en anneau.
La borne supérieure de la portée est inclusive et la borne inférieure est exclusive. Pour modifier ce comportement, vous pouvez combiner l'un des sélecteurs avec un sélecteur universel enfant. Par exemple, @scope (scope root) to (scope limit > *)
rend les deux bornes inclusives, @scope (scope root > *) to (scope limit)
rend les deux bornes exclusives, tandis que @scope (scope root > *) to (scope limit > *)
donne une borne supérieure exclusive et une borne inférieure inclusive.
Si vous souhaitez sélectionner toutes les images à l'intérieur d'un <section>
avec la classe article-body
, vous pouvez omettre la limite de portée :
@scope (.article-body) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
Ou vous pouvez inclure votre bloc @scope
en ligne dans un élément <style>
, qui se trouve lui-même dans la <section>
avec la classe article-body
:
<section class="article-body">
<style>
@scope {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
</style>
<!-- ... -->
</section>
Note :
Il est important de comprendre que, bien que @scope
vous permette d'isoler l'application des sélecteurs à des sous-arbres DOM spécifiques, elle n'isole pas complètement les styles appliqués à l'intérieur de ces sous-arbres. Cela se remarque surtout avec l'héritage : les propriétés héritées par les enfants (par exemple color
ou font-family
) seront toujours héritées, au-delà de toute limite de portée définie.
Pseudo-classe :scope
dans les blocs @scope
Dans le contexte d'un bloc @scope
, la pseudo-classe :scope
offre un moyen pratique d'appliquer directement des styles à la racine de la portée, comme ceci :
@scope (.feature) {
:scope {
background: rebeccapurple;
color: antiquewhite;
font-family: sans-serif;
}
}
Voici quelques points à considérer pour :scope
dans les blocs @scope
:
-
:scope
ajoute une définition au niveau de la classe (voir Spécificité dans @scope pour plus de détails). -
Une limite de portée peut utiliser
:scope
pour définir une relation particulière entre la limite et la racine de la portée. Par exemple :css/* figure est une limite uniquement si c'est un enfant direct de :scope */ @scope (.article-body) to (:scope > figure) { /* … */ }
-
Une limite de portée peut référencer des éléments en dehors de la racine de la portée en utilisant
:scope
. Par exemple :css/* figure est une limite uniquement si :scope est à l'intérieur de .feature */ @scope (.article-body) to (.feature :scope figure) { /* … */ }
-
Les règles de style portées ne peuvent pas sortir du sous-arbre. Les sélections comme
:scope + p
sont invalides car cette sélection serait en dehors du sous-arbre. -
Il est tout à fait possible de définir la racine et la limite de portée comme une liste de sélecteurs, auquel cas plusieurs portées seront définies. Dans l'exemple suivant, les styles sont appliqués à tout
<img>
à l'intérieur d'un<section>
avec la classearticle-hero
ouarticle-body
, mais pas s'il est imbriqué dans un<figure>
:css@scope (.article-hero, .article-body) to (figure) { img { border: 5px solid black; background-color: goldenrod; } }
Spécificité dans @scope
À l'intérieur d'une règle @scope
, les sélecteurs simples et le sélecteur d'imbrication &
se comportent comme si :where(:scope)
était préfixé au sélecteur.
Comme :where()
a une spécificité nulle, les sélecteurs simples et &
n'ajoutent aucun poids. Le poids de spécificité est déterminé par le reste du sélecteur.
Par exemple, la spécificité du sélecteur & img
est équivalente à celle de :where(:scope) img
(0-0-1).
Attention :
La spécificité de &
à l'intérieur des blocs @scope
est gérée différemment selon le moteur de navigateur et la version.
Consultez la compatibilité des navigateurs pour plus de détails.
Dans les deux cas, du bloc de code suivant, la seule spécificité provient de img
:
@scope (.article-body) {
/* img a une spécificité de 0-0-1, comme attendu */
img {
/* … */
}
/* & img a aussi une spécificité de 0-0-1 */
& img {
/* … */
}
}
En revanche, utiliser :scope
sélectionne explicitement la racine de la portée et ajoute une spécificité de niveau de classe (0-1-0), puisque :scope
est une pseudo-classe.
Dans le bloc de code suivant, :scope img
a une spécificité de 0-1-1 :
@scope (.article-body) {
/* :scope img a une spécificité de 0-1-0 + 0-0-1 = 0-1-1 */
:scope img {
/* … */
}
}
Résolution des conflits @scope
@scope
ajoute un nouveau critère à la cascade CSS : la proximité de portée. Cela signifie que lorsque deux portées ont des styles en conflit, le style ayant le plus petit nombre de sauts dans la hiérarchie de l'arbre DOM jusqu'à la racine de la portée est appliqué. Voyons un exemple pour illustrer ce principe.
Prenons l'extrait HTML suivant, où des cartes de thèmes différents sont imbriquées les unes dans les autres :
<div class="light-theme">
<p>Light theme text</p>
<div class="dark-theme">
<p>Dark theme text</p>
<div class="light-theme">
<p>Light theme text</p>
</div>
</div>
</div>
Si vous écrivez le CSS des thèmes ainsi, vous rencontrerez un problème :
.light-theme {
background: #cccccc;
}
.dark-theme {
background: #333333;
}
.light-theme p {
color: black;
}
.dark-theme p {
color: white;
}
Le paragraphe le plus à l'intérieur devrait être coloré en noir car il se trouve dans une carte de thème clair. Cependant, il est ciblé à la fois par .light-theme p
et .dark-theme p
. Comme la règle .dark-theme p
apparaît plus tard dans l'ordre du code source, elle est appliquée et le paragraphe se retrouve coloré en blanc à tort.
Pour corriger cela, vous pouvez utiliser @scope
comme suit :
@scope (.light-theme) {
:scope {
background: #cccccc;
}
p {
color: black;
}
}
@scope (.dark-theme) {
:scope {
background: #333333;
}
p {
color: white;
}
}
Désormais, le paragraphe le plus à l'intérieur est correctement coloré en noir. Cela s'explique par le fait qu'il n'est qu'à un niveau de hiérarchie du DOM de la racine de portée .light-theme
, mais à deux niveaux de la racine de portée .dark-theme
. Ainsi, le style clair l'emporte.
Note : La proximité de portée prévaut sur l'ordre du code source mais est elle-même supplantée par d'autres critères de priorité supérieure tels que l'importance, les couches et la spécificité.
Syntaxe formelle
@scope =
@scope [ ( <scope-start> ) ]? [ to ( <scope-end> ) ]? { <block-contents> }
Exemples
>Style de base dans les racines de portée
Dans cet exemple, nous utilisons deux blocs @scope
distincts pour cibler les liens à l'intérieur des éléments ayant respectivement la classe .light-scheme
et .dark-scheme
. Notez comment :scope
est utilisé pour sélectionner et mettre en forme les racines de portée elles-mêmes. Ici, les racines de portée sont les éléments <div>
auxquels les classes sont appliquées.
HTML
<div class="light-scheme">
<p>
MDN contient beaucoup d'informations sur
<a href="/fr/docs/Web/HTML">HTML</a>, <a href="/fr/docs/Web/CSS">CSS</a>, et
<a href="/fr/docs/Web/JavaScript">JavaScript</a>.
</p>
</div>
<div class="dark-scheme">
<p>
MDN contient beaucoup d'informations sur
<a href="/fr/docs/Web/HTML">HTML</a>, <a href="/fr/docs/Web/CSS">CSS</a>, et
<a href="/fr/docs/Web/JavaScript">JavaScript</a>.
</p>
</div>
CSS
@scope (.light-scheme) {
:scope {
background-color: plum;
}
a {
color: darkmagenta;
}
}
@scope (.dark-scheme) {
:scope {
background-color: darkmagenta;
color: antiquewhite;
}
a {
color: plum;
}
}
Résultat
Le code ci-dessus s'affiche ainsi :
Racines de portée et limites de portée
Dans cet exemple, nous avons un extrait HTML qui correspond à la structure DOM évoquée plus haut dans la description. Cette structure représente un résumé d'article typique. Les éléments clés à noter sont les <img>
, qui sont imbriqués à différents niveaux dans la structure.
L'objectif de cet exemple est de montrer comment utiliser une racine et une limite de portée pour mettre en forme les éléments <img>
depuis le haut de la hiérarchie, mais seulement jusqu'à (et sans inclure) l'élément <img>
à l'intérieur du <figure>
— créant ainsi une portée en anneau.
HTML
<article class="feature">
<section class="article-hero">
<h2>Titre de l'article</h2>
<img alt="image" />
</section>
<section class="article-body">
<h3>Sous-titre de l'article</h3>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam euismod
consectetur leo, nec eleifend quam volutpat vitae. Duis quis felis at
augue imperdiet aliquam. Morbi at felis et massa mattis lacinia. Cras
pharetra velit nisi, ac efficitur magna luctus nec.
</p>
<img alt="image" />
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<figure>
<img alt="image" />
<figcaption>Mon infographie</figcaption>
</figure>
</section>
<footer>
<p>Rédigé par Chris Mills.</p>
<img alt="image" />
</footer>
</article>
CSS
Dans notre CSS, nous avons deux blocs @scope
:
- Le premier bloc
@scope
définit sa racine de portée comme les éléments ayant la classe.feature
(dans ce cas, uniquement l'élément<article>
externe), illustrant comment@scope
peut être utilisé pour mettre en forme un sous-ensemble HTML spécifique. - Le second bloc
@scope
définit aussi sa racine de portée comme les éléments ayant la classe.feature
, mais définit également une limite de portéefigure
. Cela garantit que les ensembles de règles contenus ne seront appliqués qu'aux éléments correspondants à l'intérieur de la racine de portée (<article class="feature"> ... </article>
dans ce cas) qui ne sont pas imbriqués dans des éléments<figure>
descendants. Ce bloc@scope
contient un seul ensemble de règles qui met en forme les éléments<img>
avec une bordure noire épaisse et un fond doré.
/* CSS porté */
@scope (.feature) {
:scope {
background: rebeccapurple;
color: antiquewhite;
font-family: sans-serif;
}
figure {
background-color: white;
border: 2px solid black;
color: black;
padding: 10px;
}
}
/* Portée en anneau */
@scope (.feature) to (figure) {
img {
border: 5px solid black;
background-color: goldenrod;
}
}
Résultat
Dans le code affiché, notez que tous les éléments <img>
sont stylisés avec la bordure épaisse et le fond doré, sauf celui à l'intérieur de l'élément <figure>
(intitulé « Mon infographie »).
Spécifications
Specification |
---|
CSS Cascading and Inheritance Level 6> # scoped-styles> |
Compatibilité des navigateurs
>css.at-rules.scope
Loading…
css.selectors.nesting.at-scope
Loading…
Voir aussi
:scope
CSSScopeRule
- La spécificité
- Définir le sélecteur
&
dans une règle@scope
(angl.) sur css.oddbird.net (2025) - Limiter la portée de vos sélecteurs avec la règle @ CSS
@scope
(angl.) sur developer.chrome.com (2023)