I nomi CSS definiti dall'autore e il DOM ombra 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 uno stile e farvi riferimento in un'altra parte.
/* "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'ancoraggio | anchor-name |
position-anchor |
Animazione basata sullo 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.
Relazione tra i nomi e il DOM shadow
Sebbene i nomi CSS siano progettati per creare relazioni tra parti diverse di un documento o di un foglio di 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 il DOM ombra, l'esperienza di composizione delle componenti web dovrebbe essere sufficientemente espressiva da essere flessibile, ma con limitazioni sufficientemente per 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, tra i browser e tra le funzionalità e le specifiche.
Come devono funzionare insieme i nomi e il DOM ombra
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. In sintesi: un nome CSS è globale all'interno dell'ambito in cui è definito, il che significa che è possibile accedervi dagli alberi ombreggiati dei discendenti, ma non dagli alberi ombreggiati dei fratelli o degli antenati. 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 a livello di documento che definisce il funzionamento di una determinata proprietà denominata. Poiché le proprietà devono corrispondere
tra gli alberi delle ombre, la mancata corrispondenza delle dichiarazioni delle proprietà creerebbe risultati
inaspettati, pertanto le dichiarazioni @property
vengono specificate per essere appiattite e risolte
in base all'ordine del documento.
Come dovrebbe funzionare la regola con ::part
Le parti in ombra
espongono un elemento all'interno di un albero in 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.
- Quindi, applica lo stile esterno come definito in
::part
. Si tratta dello stile "personalizzato" della parte. - Poi, applica qualsiasi stile interno definito insieme a
!important
. In questo modo, un elemento personalizzato può 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 lo stesso ambito dell'elemento. Questo perché per applicare uno stile a un elemento devi accedere all'handle dell'elemento e quindi all'elemento radice ombra stesso.
Come funzionano insieme i nomi CSS e il DOM ombra
Sebbene le regole precedenti siano ben definite e coerenti, le implementazioni attuali non lo riflettono sempre.
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 il funzionamento pratico di queste funzionalità, abbiamo creato la seguente pagina: https://css-names-in-the-shadow.glitch.me/. Questa pagina contiene diversi iframe, ognuno incentrato su una delle funzionalità e che testa sei scenari:
- Riferimento esterno a un nome esterno: non è coinvolto il DOM ombra, quindi dovrebbe funzionare.
- Riferimento esterno a un nome interno: questa operazione non dovrebbe funzionare, in quanto significherebbe che il nome definito nel contesto shadow è stato trafugato.
- 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 a cui fa 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 nei vari browser:
@font-face
viene appiattito nell'ambito principale in Safari.- Chromium non consente l'ereditarietà 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 si esamina lo snapshot dell'attuale stato dell'interoperabilità in merito ai nomi CSS e allo shadow DOM, l'esperienza è incoerente e con bug. 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.