Door de auteur gedefinieerde CSS-namen en schaduw-DOM: in specificatie en in de praktijk

Door de auteur gedefinieerde CSS-namen en de schaduw-DOM zouden moeten samenwerken. Browsers zijn echter inconsistent met de specificatie, soms met elkaar, en elke CSS-naam is op een iets andere manier inconsistent.

Dit artikel documenteert de huidige status van hoe door de auteur gedefinieerde CSS-namen zich gedragen in schaduwbereiken, in de hoop dat dit als leidraad kan dienen om de interoperabiliteit in de nabije toekomst te verbeteren.

Wat zijn door de auteur gedefinieerde CSS-namen?

Door de auteur gedefinieerde CSS-namen zijn een relatief oud CSS-syntaxismechanisme, oorspronkelijk geïntroduceerd voor de @keyframes regel, die een <keyframe-name> definieert als een aangepaste ident of een tekenreeks. Het doel van dit concept is om iets in een deel van een stylesheet te declareren en ernaar te verwijzen in een ander deel.

/* "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;
}

Andere CSS-functies die CSS-namen gebruiken zijn lettertypen, eigenschapsdeclaraties, containerquery's en, meer recentelijk, weergaveovergangen, ankerpositionering en scrollgestuurde animaties. De volgende niet-uitgebreide tabel bevat namen waarvan Chrome de status controleert.

Functie Naamverklaring Naamreferentie
Sleutelframes @keyframes animation-name
Lettertypen @font-face { }
@font-palette-values
font-family
font-palette
Eigendomsverklaringen @property Elke aangepaste eigenschap
Overgang bekijken view-transition-name
view-transition-class
::view-transition-group()
Anker positionering anchor-name position-anchor
Scrollgestuurde animatie animation-timeline view-timeline-name
scroll-timeline-name
Tegenstijl @counter-style
Counter-reset
counter-set
counter-increment
list-style
Containerquery's container-name @container
CSS-variabele --something var(--something)
Bladzijde @page

Zoals je in de tabel kunt zien, heeft een CSS- naam meestal een overeenkomstige CSS- referentie . animation-name is bijvoorbeeld een verwijzing naar de naam @keyframes . CSS-namen verschillen van namen die in de DOM zijn gedefinieerd, zoals attributen en tagnamen, omdat ze worden gedeclareerd en er vervolgens naar wordt verwezen binnen de context van stylesheets.

Hoe namen zich verhouden tot de schaduw-DOM

Terwijl CSS-namen zijn gebouwd om relaties tussen verschillende delen van een document of stylesheet te creëren, is Shadow DOM gebouwd om het tegenovergestelde te doen. Het kapselt relaties in, zodat ze niet lekken via webcomponenten die hun eigen naamruimte zouden moeten hebben.

Door CSS-namen en de schaduw-DOM samen te brengen, moet de ervaring van het samenstellen van webcomponenten expressief genoeg aanvoelen om flexibel te zijn, maar ook beperkt genoeg om stabiel te zijn.

Dit is in theorie goed. In de praktijk zijn browsers inconsistent in de manier waarop CSS-namen samenwerken met de schaduw-DOM, zowel tussen functies in dezelfde browser, tussen browsers, als tussen de functies en de specificatie.

Hoe namen en de schaduw-DOM moeten samenwerken

Om het probleem te begrijpen, is het de moeite waard om te begrijpen hoe deze delen van CSS in theorie zouden moeten samenwerken.

De algemene regel

De algemene regel voor hoe CSS-namen zich gedragen in schaduwbomen is gedefinieerd in de CSS Scoping Level 1-specificatie . Samenvattend: een CSS-naam is globaal binnen het bereik waarin deze is gedefinieerd, wat betekent dat deze toegankelijk is via schaduwbomen van afstammelingen, maar niet van schaduwbomen van broers en zussen of voorouders. Merk op dat dit anders is dan namen op het webplatform, zoals element-ID's, die binnen hetzelfde boombereik zijn ingekapseld.

Uitzondering op de regel: @property

In tegenstelling tot andere CSS-namen worden CSS-eigenschappen niet ingekapseld door schaduw-DOM. Integendeel, ze zijn de gebruikelijke manier om parameters door te geven aan verschillende schaduwbomen. Dit maakt de @property descriptor speciaal: deze zou zich moeten gedragen als een document-globale typedeclaratie die definieert hoe een bepaalde benoemde eigenschap zich gedraagt. Omdat eigenschappen over schaduwbomen heen moeten overeenkomen, zou een niet-overeenkomende eigenschapsdeclaratie tot onverwachte resultaten leiden. Daarom worden @property declaraties gespecificeerd om te worden afgevlakt en opgelost volgens de documentvolgorde.

Hoe de regel zou moeten werken met ::part

Schaduwdelen stellen een element binnen een schaduwboom bloot aan de bovenliggende boom. Door dit te doen kan de bovenliggende boom toegang krijgen tot dat element en het ook opmaken met behulp van het ::part element.

Omdat ::part toestaat dat twee boomscopes hetzelfde element opmaken, wordt de volgende cascadevolgorde gespecificeerd:

  1. Controleer eerst de stijl binnen de schaduwcontext. Dit is de "standaard" stijl van het onderdeel.
  2. Pas vervolgens de externe stijl toe zoals gedefinieerd in ::part . Dit is de "aangepaste" stijl van het onderdeel.
  3. Pas vervolgens elke interne stijl toe die samen met !important is gedefinieerd. Hierdoor kan een aangepast element verklaren dat een bepaalde eigenschap van een bepaald onderdeel niet kan worden aangepast door ::part .

Dit betekent dat er niet naar namen vanuit de schaduw-DOM kan worden verwezen vanuit een ::part , omdat de ::part een host-scoped stijl is in plaats van een shadow-scoped stijl. Bijvoorbeeld:

// 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;  
}

Hoe de regel zou moeten werken met inline stijlen

In tegenstelling tot ::part zijn inline stijlen met het style attribuut, of stijlen die de stijl programmatisch instellen met behulp van script, van toepassing op het bereik van het element. Dat komt omdat je, om een ​​stijl op een element toe te passen, toegang nodig hebt tot de elementhandle, en dus tot de schaduwwortel zelf.

Hoe CSS-namen en de schaduw-DOM in werkelijkheid samenwerken

Hoewel de voorgaande regels goed gedefinieerd en consistent zijn, weerspiegelen de huidige implementaties dat niet altijd. In de praktijk werkt @property op een consistente manier in alle browsers anders dan de specificaties, en de meeste andere functies bevatten openstaande bugs (sommige ervan zijn nog niet vrijgegeven, dus er is tijd om ze te repareren).

Om te testen en te demonstreren hoe deze functies in de praktijk werken, hebben we de volgende pagina gemaakt: https://css-names-in-the-shadow.glitch.me/ . Deze pagina bevat verschillende iframes, elk gericht op een van de functies en het testen van zes scenario's:

  • Externe verwijzing naar een externe naam : er is geen schaduw-DOM bij betrokken, dit zou moeten werken.
  • Uiterlijke verwijzing naar een innerlijke naam : dit zou niet moeten werken, omdat dat zou betekenen dat de naam die in de schaduwcontext is gedefinieerd, is gelekt.
  • Innerlijke verwijzing naar uiterlijke naam : dit zou moeten werken, omdat namen met een boombereik worden overgenomen door schaduwwortels.
  • Innerlijke verwijzing naar innerlijke naam : dit zou moeten werken, omdat beide namen van de verwijzing zich in hetzelfde bereik bevinden.
  • ::part verwijzing naar buitenste naam : dit zou moeten werken, omdat zowel het ::part als de naam in dezelfde scope worden gedeclareerd.
  • ::part verwijzing naar innerlijke naam : dit zou niet moeten werken, omdat de buitenste scope geen kennis zou moeten verwerven over namen die binnen de schaduw-DOM zijn gedeclareerd.

@keyframes

Zoals gedefinieerd in de specificatie, zou u moeten kunnen verwijzen naar sleutelframenamen vanuit een schaduwwortel, zolang de @keyframes at-regel zich in een bovenliggend bereik bevindt. In de praktijk implementeert geen enkele browser dit gedrag, en er kan alleen naar de sleutelframedefinities worden verwezen in het bereik waarin ze zijn gedefinieerd. Zie uitgave 10540 .

@property

Zoals gedefinieerd in de specificatie, wordt elke declaratie van @property afgevlakt naar het documentbereik. Tegenwoordig kunt u echter in alle browsers alleen @property declareren in het documentbereik en worden @property declaraties binnen schaduwwortels genegeerd.
Zie uitgave 10541 .

Browserspecifieke bugs

De andere functies vertonen geen consistent gedrag in alle browsers:

  • @font-face is afgevlakt tot het hoofdbereik in Safari.
  • Chromium staat het overnemen van @anchor-name regels in een schaduwroot niet toe
  • @scroll-timeline-name en @view-timeline-name hebben niet de juiste scope op ::part (ook in Chromium).
  • Geen enkele browser staat het declareren @font-palette-values in een schaduwwortel toe.
  • view-transition-class kan worden gedefinieerd binnen een schaduwwortel (de overgang zelf bevindt zich buiten de schaduwwortel).
  • Firefox geeft ::part toegang tot namen van innerlijke schaduwen (containerquery's, sleutelframes).
  • Firefox en Safari respecteren @counter-style in een schaduwroot niet.

Houd er rekening mee dat counter-reset , counter-set , counter-increment enigszins verschillende regels hebben omdat het impliciete namen zijn, en dat het declareren van CSS-eigenschappen een gevestigde en goed geteste set regels heeft.

Conclusie

Het slechte nieuws is dat bij het onderzoeken van de momentopname van de huidige interoperabiliteitsstatus met betrekking tot CSS-namen en de schaduw-DOM, de ervaring inconsistent en met fouten is. Geen van de functies die we hier hebben onderzocht, gedraagt ​​zich consistent in alle browsers en volgens de specificaties. Het goede nieuws is dat de delta om de ervaring consistent te maken een eindige lijst van bugs en spec-problemen is. Laten we dit oplossen! In de tussentijd kan dit overzicht je hopelijk helpen als je worstelt met de inconsistenties die in dit artikel worden beschreven.