Les noms CSS définis par les auteurs et le Shadow DOM sont censés fonctionner ensemble. Toutefois, les navigateurs ne respectent pas la spécification, parfois les uns les autres, et chaque nom CSS est incohérent d'une manière légèrement différente.
Cet article décrit l'état actuel du comportement des noms CSS définis par l'auteur dans les portées d'ombre, dans l'espoir qu'il puisse servir de guide pour améliorer l'interopérabilité dans un avenir proche.
Que sont les noms CSS définis par l'auteur ?
Les noms CSS définis par l'auteur sont un mécanisme de syntaxe CSS relativement ancien, introduit à l'origine pour la règle @keyframes
, qui définit un <keyframe-name>
comme un identifiant personnalisé ou une chaîne. L'objectif de ce concept est de déclarer quelque chose dans une partie d'une feuille de style, puis de s'y référer dans une autre partie.
/* "fade-in" is a CSS name, representing a set of keyframes */
@keyframes fade-in {
from { opacity: 0 };
to { opacity: 1 }
}
.card {
/* "fade-in" is a reference to the above keyframes */
animation-name: fade-in;
}
Les autres fonctionnalités CSS qui utilisent des noms CSS sont les polices, les déclarations de propriétés, les requêtes de conteneur et, plus récemment, les transitions de vue, le positionnement des ancres et les animations basées sur le défilement. Le tableau suivant, non exhaustif, inclut les noms dont l'état est vérifié par Chrome.
Fonctionnalité | Déclaration de nom | Référence de nom |
---|---|---|
Images clés | @keyframes |
animation-name |
Polices | @font-face { }
@font-palette-values |
font-family
font-palette |
Déclarations de propriétés | @property Toute déclaration de propriété personnalisée non enregistrée |
var() |
Afficher les transitions | view-transition-name
view-transition-class |
Éléments pseudo ::view-transition-* |
Positionnement des ancres | anchor-name |
position-anchor |
Animation liée au défilement | view-timeline-name
scroll-timeline-name |
animation-timeline |
Styles de liste | @counter-style |
list-style |
Compteurs | counter-reset
counter-set
counter-increment |
|
Requêtes de conteneur | container-name |
@container |
Page | page |
@page |
Comme vous pouvez le voir dans le tableau, un nom CSS possède généralement une référence CSS correspondante. Par exemple, animation-name
fait référence au nom @keyframes
. Les noms CSS sont différents des noms définis dans le DOM, tels que les attributs et les noms de balises, car ils sont déclarés, puis référencés dans le contexte des feuilles de style.
Lien entre les noms et le Shadow DOM
Alors que les noms CSS sont conçus pour créer des relations entre différentes parties d'un document ou d'une feuille de style, le DOM ombragé est conçu pour faire le contraire. Il encapsule les relations afin d'éviter qu'elles ne fuient entre les composants Web censés avoir leur propre espace de noms.
En combinant les noms CSS et le DOM ombragé, l'expérience de composition des composants Web doit être suffisamment expressive pour être flexible, mais suffisamment limitée pour être stable.
C'est une bonne théorie. En pratique, les navigateurs ne sont pas cohérents dans la façon dont les noms CSS interagissent avec le Shadow DOM, à la fois entre les fonctionnalités du même navigateur, entre les navigateurs et entre les fonctionnalités et les spécifications.
Fonctionnement des noms et du DOM ombragé
Pour comprendre le problème, il est utile de comprendre comment ces parties du CSS doivent fonctionner ensemble en théorie.
Règle générale
La règle générale concernant le comportement des noms CSS dans les arbres d'ombre est définie dans la spécification CSS Scoping Level 1. Pour résumer: un nom CSS est global dans le champ d'application dans lequel il est défini, ce qui signifie qu'il est accessible à partir des arbres d'ombre descendants, mais pas à partir des arbres d'ombre frères ou ancêtres. Notez que cela diffère des noms utilisés sur la plate-forme Web, tels que les ID d'élément, qui sont encapsulés dans le même champ d'application d'arborescence.
Exception à la règle: @property
Contrairement aux autres noms CSS, les propriétés CSS ne sont pas encapsulées par le Shadow DOM.
Il s'agit plutôt du moyen courant de transmettre des paramètres entre différents arbres d'ombre.
Cela rend le descripteur @property
spécial: il est censé se comporter comme une déclaration de type globale du document qui définit le comportement d'une propriété nommée particulière. Étant donné que les propriétés doivent correspondre entre les arbres d'ombre, une non-correspondance entre les déclarations de propriétés créerait des résultats inattendus. Par conséquent, les déclarations @property
sont spécifiées pour être aplaties et résolues en fonction de l'ordre des documents.
Fonctionnement de la règle avec ::part
Les parties d'ombre exposent un élément dans un arbre d'ombre à son arbre parent. L'arborescence parente peut ainsi accéder à cet élément et lui appliquer un style à l'aide de l'élément ::part
.
Étant donné que ::part
permet à deux portées d'arborescence de styliser le même élément, l'ordre en cascade suivant est spécifié:
- Commencez par vérifier le style dans le contexte de l'ombre. Il s'agit du style "par défaut" de la pièce.
- Appliquez ensuite le style externe tel que défini dans
::part
. Il s'agit du style "personnalisé" de la pièce. - Appliquez ensuite tout style interne défini avec
!important
. Cela permet à un élément personnalisé de déclarer qu'une certaine propriété d'une certaine partie n'est pas personnalisable par::part
.
Cela signifie que les noms du Shadow DOM ne peuvent pas être référencés à partir d'un ::part
, car le ::part
est un style de portée hôte plutôt qu'un style de portée "shadow". Exemple :
// inside the shadow DOM:
@keyframes fade-in {
from { opacity: 0}
}
// This shouldn't work!
// The host style shouldn't know the name "fade-in"
::part(slider) {
animation-name: fade-in;
}
Fonctionnement de la règle avec les styles intégrés
Contrairement à ::part
, les styles intégrés avec l'attribut style
ou ceux qui définissent le style de manière programmatique à l'aide d'un script sont limités à l'étendue de l'élément. En effet, pour appliquer un style à un élément, vous devez accéder à la poignée de l'élément, et donc à la racine de l'ombre elle-même.
Comment les noms CSS et le Shadow DOM fonctionnent ensemble en réalité
Bien que les règles précédentes soient bien définies et cohérentes, les implémentations actuelles ne le reflètent pas toujours.
En pratique, @property
fonctionne différemment de la spécification de manière cohérente entre les navigateurs, et la plupart des autres fonctionnalités comportent des bugs ouverts (certains d'entre eux n'ont pas encore été publiés, il est donc encore temps de les corriger).
Pour tester et montrer comment ces fonctionnalités fonctionnent en pratique, nous avons créé la page suivante : https://css-names-in-the-shadow.glitch.me/. Cette page comporte plusieurs iFrames, chacun axé sur l'une des fonctionnalités et testant six scénarios:
- Référence externe à un nom externe: aucun Shadow DOM n'est impliqué, cela devrait fonctionner.
- Référence externe à un nom interne: cela ne devrait pas fonctionner, car cela signifierait que le nom défini dans le contexte Shadow a été divulgué.
- Référence interne au nom externe: cela devrait fonctionner, car les noms à l'échelle de l'arborescence sont hérités par les racines fantômes.
- Référence interne au nom interne: cela devrait fonctionner, car le nom de la référence se trouve dans le même champ d'application.
- Référence
::part
au nom externe: cela devrait fonctionner, car::part
et le nom sont déclarés dans le même champ d'application. - Référence
::part
au nom interne: cela ne devrait pas fonctionner, car le champ d'application externe ne doit pas connaître les noms déclarés dans le DOM fantôme.
@keyframes
Comme indiqué dans la spécification, vous devriez pouvoir faire référence aux noms de clés d'animation à partir d'une racine d'ombre, à condition que la règle at-rule @keyframes
se trouve dans un champ d'application d'ancêtre. En pratique, aucun navigateur ne met en œuvre ce comportement, et les définitions d'images clés ne peuvent être référencées que dans le champ d'application dans lequel elles sont définies. Consultez le problème 10540.
@property
Comme défini dans la spécification, toute déclaration de @property
sera aplatie dans le champ d'application du document. Cependant, aujourd'hui, dans tous les navigateurs, vous ne pouvez déclarer @property
que dans le champ d'application du document, et les déclarations @property
dans les racines d'ombre sont ignorées.
Consultez le problème 10541.
Bugs spécifiques au navigateur
Les autres fonctionnalités ne présentent pas un comportement cohérent entre les navigateurs:
@font-face
est aplati au niveau du champ d'application racine dans Safari.- Chromium n'autorise pas l'héritage des règles
anchor-name
dans un nœud racine fantôme - Les champs d'application de
scroll-timeline-name
etview-timeline-name
ne sont pas correctement définis sur::part
(également dans Chromium). - Aucun navigateur n'autorise la déclaration de
@font-palette-values
dans des racines d'ombre. view-transition-class
peut être défini dans une racine d'ombre (la transition elle-même se trouve en dehors de la racine d'ombre).- Firefox permet à
::part
d'accéder aux noms d'ombres internes (requêtes de conteneur, images clés). - Firefox et Safari ne respectent pas
@counter-style
dans un root d'ombre.
Notez que counter-reset
, counter-set
et counter-increment
ont des règles légèrement différentes, car il s'agit de noms implicites. De plus, les propriétés CSS déclarées disposent d'un ensemble de règles établi et bien testé.
Conclusion
Malheureusement, lorsque vous examinez l'instantané de l'état d'interopérabilité actuel pour les noms CSS et le Shadow DOM, l'expérience est incohérente et génère des bugs. Aucune des fonctionnalités que nous avons examinées ici ne se comporte de manière cohérente d'un navigateur à l'autre et conformément aux spécifications. La bonne nouvelle, c'est que le delta permettant de rendre l'expérience cohérente est une liste limitée de bugs et de problèmes de spécifications. Résolvons à présent ce problème. En attendant, nous espérons que cet aperçu vous aidera si vous rencontrez des difficultés avec les incohérences décrites dans cet article.