I nomi CSS definiti dallo scrittore e lo shadow DOM dovrebbero funzionare insieme. Tuttavia, i browser non sono coerenti con la specifica, a volte tra di loro, e ogni nome CSS non è coerente in modo leggermente diverso.
Questo articolo descrive lo stato attuale del comportamento dei nomi CSS definiti dall'autore nei vari ambiti shadow, con la speranza che possa servire da guida per migliorare l'interoperabilità nel prossimo futuro.
Che cosa sono i nomi CSS definiti dall'autore?
I nomi CSS definiti dall'autore sono un meccanismo di sintassi CSS relativamente antico, originariamente introdotto per la regola @keyframes
, che definisce un <keyframe-name>
come un ident personalizzato o una stringa. Lo scopo di questo concetto è dichiarare
qualcosa in una parte di un foglio di stile e farvi riferimento in un'altra.
/* "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;
}
Altre funzionalità CSS che utilizzano i nomi CSS sono i caratteri, le dichiarazioni delle proprietà, le query dei contenitori e, più di recente, le transizioni di visualizzazione, il posizionamento dell'ancora e le animazioni basate sullo scorrimento. La seguente tabella non esaustiva include i nomi di cui Chrome controlla lo stato.
Funzionalità | Dichiarazione del nome | Riferimento nome |
---|---|---|
Fotogrammi chiave | @keyframes |
animation-name |
Caratteri | @font-face { }
@font-palette-values |
font-family
font-palette |
Dichiarazioni relative alla proprietà | @property Qualsiasi dichiarazione di proprietà personalizzata non registrata |
var() |
Visualizza transizioni | view-transition-name
view-transition-class |
::view-transition-* elementi pseudo |
Posizionamento dell'ancora | anchor-name |
position-anchor |
Animazione con scorrimento | view-timeline-name
scroll-timeline-name |
animation-timeline |
Stili di elenco | @counter-style |
list-style |
Contatori | counter-reset
counter-set
counter-increment |
|
Query sui contenitori | container-name |
@container |
Pagina | page |
@page |
Come puoi vedere nella tabella, un nome CSS ha in genere un corrispondente riferimento CSS. Ad esempio, animation-name
è un riferimento al nome @keyframes
. I nomi CSS sono diversi da quelli definiti nel DOM, come gli attributi
e i nomi dei tag, in quanto vengono dichiarati e poi richiamati nel contesto degli stile.
Correlazione dei nomi allo shadow DOM
Sebbene i nomi CSS siano progettati per creare relazioni tra parti diverse di un documento o di uno stile, il DOM ombra è progettato per fare il contrario. Incapsula le relazioni in modo che non vengano divulgate tra i componenti web che dovrebbero avere un proprio spazio dei nomi.
Combinando i nomi CSS e lo shadow DOM, l'esperienza di composizione dei componenti web dovrebbe sembrare abbastanza espressiva da essere flessibile, ma abbastanza limitata da essere stabile.
In teoria è una buona idea. In pratica, i browser non sono coerenti nel modo in cui i nomi CSS interagiscono con lo shadow DOM, sia tra le funzionalità nello stesso browser, nei vari browser, sia tra le funzionalità e la specifica.
Modalità di interazione tra nomi e shadow DOM
Per comprendere il problema, è utile capire come queste parti del CSS dovrebbero funzionare insieme in teoria.
La regola generale
La regola generale relativa al comportamento dei nomi CSS nei vari alberi ombre è definita nella specifica CSS Scoping Level 1. Riassumendo: un nome CSS è globale all'interno dell'ambito in cui è definito, il che significa che è possibile accedervi dagli alberi ombre discendenti, ma non da quelli di pari livello o predecessore. Tieni presente che questo è diverso dai nomi della piattaforma web come gli ID elemento, che sono incapsulati nello stesso ambito dell'albero.
Eccezione alla regola: @property
A differenza di altri nomi CSS, le proprietà CSS non sono incapsulate dal DOM ombra.
Piuttosto, sono il mezzo comune per trasmettere parametri tra diversi alberi
ombre.
Questo rende speciale il descrittore @property
: dovrebbe comportarsi come una dichiarazione di tipo document-globale che definisce il comportamento di una determinata proprietà con nome. Poiché le proprietà devono corrispondere
tra gli alberi ombra, la mancata corrispondenza delle dichiarazioni delle proprietà genererebbe risultati imprevisti, quindi le dichiarazioni @property
vengono specificate in modo da essere suddivise e risolte in base all'ordine del documento.
Come dovrebbe funzionare la regola con ::part
Le parti ombra espongono un elemento all'interno di un albero ombra al relativo albero principale. In questo modo, la
struttura ad albero principale può accedere all'elemento e modificarne lo stile utilizzando l'elemento ::part
.
Poiché ::part
consente a due ambiti dell'albero di applicare stili allo stesso elemento, viene specificato il seguente ordine di applicazione in cascata:
- Innanzitutto, controlla lo stile all'interno del contesto shadow. Si tratta dello stile "predefinito" del componente.
- poi applica lo stile esterno come definito in
::part
. Si tratta dello stile "personalizzato" della parte. - Poi, applica eventuali stili interni definiti insieme a
!important
. Ciò consente a un elemento personalizzato di dichiarare che una determinata proprietà di una determinata parte non è personalizzabile da::part
.
Ciò significa che non è possibile fare riferimento ai nomi all'interno dello shadow DOM da un ::part
, in quanto ::part
è uno stile basato sull'host anziché uno stile basato sullo shadow. Ad esempio:
// 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;
}
Come dovrebbe funzionare la regola con gli stili in linea
A differenza di ::part
, gli stili incorporati con l'attributo style
o quelli che impostano lo stile tramite script in modo programmatico hanno come ambito l'elemento. Questo perché per applicare uno stile a un elemento devi accedere all'handle dell'elemento e quindi all'elemento radice ombra stesso.
Come i nomi CSS e lo shadow DOM funzionano insieme nella realtà
Sebbene le regole precedenti siano ben definite e coerenti, le implementazioni attuali non sempre riflettono questo aspetto.
In pratica, @property
funziona in modo diverso rispetto alle specifiche in modo coerente tra i browser e la maggior parte delle altre funzionalità presenta bug aperti (alcune non sono ancora state rilasciate, quindi c'è tempo per correggerli).
Per testare e dimostrare come funzionano queste funzionalità nella pratica, abbiamo creato la seguente pagina: https://css-names-in-the-shadow.glitch.me/. Questa pagina contiene diversi iframe, ciascuno incentrato su una delle funzionalità e i sei scenari di test:
- Riferimento esterno a un nome esterno: non è coinvolto il DOM ombra, quindi dovrebbe funzionare.
- Riferimento esterno a un nome interno: non dovrebbe funzionare, perché ciò significherebbe che il nome definito nel contesto shadow è trapelato.
- Riferimento interno al nome esterno: dovrebbe funzionare, poiché i nomi a livello di albero vengono ereditati dalle radici shadow.
- Riferimento interno al nome interno: dovrebbe funzionare, poiché sia il nome del riferimento sia il nome dell'elemento di riferimento si trovano nello stesso ambito.
- Riferimento a
::part
al nome esterno: dovrebbe funzionare, poiché sia::part
che il nome sono dichiarati nello stesso ambito. ::part
riferimento al nome interno: non dovrebbe funzionare, poiché l'ambito esterno non dovrebbe acquisire informazioni sui nomi dichiarati all'interno del DOM ombra.
@keyframes
Come definito nella specifica, dovresti essere in grado di fare riferimento ai nomi dei fotogrammi chiave
dall'interno di un elemento shadow root, purché la regola at @keyframes
sia in un ambito
antenato. In pratica, nessun browser implementa questo comportamento e alle definizioni dei fotogrammi chiave si può fare riferimento solo nell'ambito in cui sono definite. Consulta
Issue 10540.
@property
Come definito nella specifica, qualsiasi dichiarazione di @property
verrà
appiattita all'ambito del documento. Tuttavia, al momento, in tutti i browser puoi dichiarare @property
solo nell'ambito del documento e le dichiarazioni @property
all'interno delle radici shadow vengono ignorate.
Leggi il problema 10541.
Bug specifici del browser
Le altre funzionalità non mostrano un comportamento coerente tra i vari browser:
@font-face
viene appiattito nell'ambito principale in Safari.- Chromium non consente l'eredità delle regole
anchor-name
in un elemento shadow root scroll-timeline-name
eview-timeline-name
non sono inclusi correttamente in::part
(anche in Chromium).- Nessun browser consente di dichiarare
@font-palette-values
in una radice ombra. view-transition-class
può essere definito all'interno di un elemento shadow root (la transizione stessa si trova all'esterno dell'elemento shadow root).- Firefox consente a
::part
di accedere ai nomi delle ombre interne (query dei contenitori,keyframe). - Firefox e Safari non rispettano
@counter-style
in un elemento shadow root.
Tieni presente che counter-reset
, counter-set
, counter-increment
hanno regole leggermente diverse perché sono nomi impliciti e le proprietà CSS dichiarate hanno un insieme di regole stabilito e ben testato.
Conclusione
La cattiva notizia è che quando esamini l'istantanea dello stato di interoperabilità attuale per quanto riguarda i nomi CSS e lo shadow DOM, l'esperienza è incoerente e buggy. Nessuna delle funzionalità che abbiamo esaminato qui si comporta in modo coerente su tutti i browser e in base alle specifiche. La buona notizia è che il delta per rendere l'esperienza coerente è un elenco finito di bug e problemi relativi alle specifiche. Risolviamo il problema. Nel frattempo, questa panoramica può aiutarti se hai difficoltà con le incoerenze descritte in questo articolo.