Se supone que los nombres de CSS definidos por el autor y el DOM de sombra funcionan juntos. Sin embargo, los navegadores no son coherentes con la especificación, a veces entre sí, y cada nombre de CSS es incoherente de una manera ligeramente diferente.
En este artículo, se documenta el estado actual del comportamiento de los nombres de CSS definidos por el autor en los alcances de sombras, con la esperanza de que pueda servir como guía para mejorar la interoperabilidad en un futuro cercano.
¿Qué son los nombres de CSS definidos por el autor?
Los nombres de CSS definidos por el autor son un mecanismo de sintaxis de CSS relativamente antiguo, que se introdujo originalmente para la regla @keyframes
, que define un <keyframe-name>
como una identificación personalizada o una cadena. El propósito de este concepto es declarar algo en una parte de una hoja de estilo y hacer referencia a ella en otra 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;
}
Otras funciones de CSS que usan nombres de CSS son las fuentes, las declaraciones de propiedades, las consultas de contenedor y, más recientemente, las transiciones de vista, el posicionamiento de anclaje y las animaciones impulsadas por el desplazamiento. En la siguiente tabla no exhaustiva, se incluyen los nombres cuyos estados Chrome verifica.
Función | Declaración de nombre | Referencia de nombre |
---|---|---|
Fotogramas clave | @keyframes |
animation-name |
Fuentes | @font-face { }
@font-palette-values |
font-family
font-palette |
Declaraciones de propiedades | @property Cualquier declaración de propiedad personalizada no registrada |
var() |
Cómo ver transiciones | view-transition-name
view-transition-class |
Pseudoelementos ::view-transition-* |
Posicionamiento de la ancla | anchor-name |
position-anchor |
Animación impulsada por el desplazamiento | view-timeline-name
scroll-timeline-name |
animation-timeline |
Estilos de lista | @counter-style |
list-style |
Contadores | counter-reset
counter-set
counter-increment |
|
Consultas de contenedores | container-name |
@container |
Página | page |
@page |
Como puedes ver en la tabla, un nombre de CSS suele tener una referencia de CSS correspondiente. Por ejemplo, animation-name
es una referencia al nombre @keyframes
. Los nombres de CSS son diferentes de los nombres definidos en el DOM, como los atributos y los nombres de etiquetas, ya que se declaran y, luego, se hace referencia a ellos en el contexto de los diseños de página.
Cómo se relacionan los nombres con el shadow DOM
Si bien los nombres de CSS se compilan para crear relaciones entre diferentes partes de un documento o una hoja de estilo, Shadow DOM se compila para hacer lo contrario. Encapsula las relaciones para que no se filtren en los componentes web que deberían tener su propio espacio de nombres.
Cuando se combinan los nombres de CSS y el DOM sombreado, la experiencia de composición de componentes web debería ser lo suficientemente expresiva como para ser flexible, pero lo suficientemente restringida como para ser estable.
Esto es bueno en teoría. En la práctica, los navegadores son incoherentes en la forma en que los nombres de CSS interoperan con el shadow DOM, tanto entre las funciones del mismo navegador, entre navegadores y entre las funciones y la especificación.
Cómo deben funcionar juntos los nombres y el DOM sombreado
Para comprender el problema, vale la pena comprender cómo deberían funcionar juntas estas partes del CSS en teoría.
La regla general
La regla general sobre cómo se comportan los nombres de CSS en los árboles de sombras se define en la especificación de nivel 1 de CSS Scoping. En resumen, un nombre de CSS es global dentro del alcance en el que se define, lo que significa que se puede acceder a él desde árboles de sombras descendientes, pero no desde árboles de sombras hermanos o ancestros. Ten en cuenta que esto es diferente de los nombres en la plataforma web, como los IDs de elementos, que se encapsulan dentro del mismo alcance del árbol.
Excepción a la regla: @property
A diferencia de otros nombres de CSS, las propiedades de CSS no están encapsuladas por Shadow DOM.
En cambio, son el medio común para pasar parámetros a través de diferentes árboles de sombras.
Esto hace que el descriptor @property
sea especial: se supone que se comporta como una declaración de tipo global del documento que define cómo actúa una propiedad nombrada en particular. Debido a que las propiedades deben coincidir en todos los árboles de sombras, la falta de coincidencia de las declaraciones de propiedades crearía resultados inesperados, por lo que se especifica que las declaraciones de @property
se aplanen y resuelvan según el orden del documento.
Cómo debería funcionar la regla con ::part
Las partes de sombra exponen un elemento dentro de un árbol de sombras a su árbol superior. De esta manera, el árbol superior puede acceder a ese elemento y también aplicarle un diseño con el elemento ::part
.
Dado que ::part
permite que dos alcances de árbol apliquen diseño al mismo elemento, se especifica el siguiente orden en cascada:
- Primero, verifica el estilo dentro del contexto de sombra. Este es el estilo “predeterminado” de la pieza.
- Luego, aplica el estilo externo como se define en
::part
. Este es el estilo “personalizado” de la pieza. - Luego, aplica cualquier estilo interno que se defina junto con
!important
. Esto permite que un elemento personalizado declare que::part
no puede personalizar una propiedad determinada de una parte determinada.
Esto significa que no se puede hacer referencia a los nombres dentro del shadow DOM desde un ::part
, ya que ::part
es un estilo con el alcance del host en lugar de un estilo con el alcance de la sombra. Por ejemplo:
// 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;
}
Cómo debería funcionar la regla con los estilos intercalados
A diferencia de ::part
, los estilos intercalados con el atributo style
, o aquellos que configuran el estilo de forma programática con una secuencia de comandos, se aplican al elemento al que se aplica el estilo. Esto se debe a que, para aplicar un estilo a un elemento, necesitas acceso al control del elemento y, por lo tanto, a la raíz de sombra.
Cómo funcionan juntos los nombres de CSS y el DOM sombreado en la realidad
Si bien las reglas anteriores están bien definidas y son coherentes, las implementaciones actuales no siempre lo reflejan.
En la práctica, @property
funciona de manera diferente a la especificación de una manera coherente en todos los navegadores, y la mayoría de las otras funciones tienen errores abiertos (algunos de los cuales aún no se lanzaron, por lo que hay tiempo para corregirlos).
Para probar y demostrar cómo funcionan estas funciones en la práctica, creamos la siguiente página: https://css-names-in-the-shadow.glitch.me/. Esta página tiene varios iframes, cada uno enfocado en una de las funciones y que prueba seis situaciones:
- Referencia externa a un nombre externo: No hay shadow DOM involucrado, esto debería funcionar.
- Referencia externa a un nombre interno: Esto no debería funcionar, ya que eso significaría que se filtró el nombre definido en el contexto de la sombra.
- Referencia interna al nombre externo: Esto debería funcionar, ya que las raíces de sombra heredan los nombres centrados en el árbol.
- Referencia interna al nombre interno: Esto debería funcionar, ya que el nombre de la referencia está en el mismo alcance.
::part
hace referencia al nombre externo: Esto debería funcionar, ya que::part
y el nombre se declaran en el mismo alcance.- Referencia de
::part
al nombre interno: Esto no debería funcionar, ya que el alcance externo no debería obtener información sobre los nombres declarados dentro del DOM sombreado.
@keyframes
Como se define en la especificación, deberías poder hacer referencia a los nombres de fotogramas clave desde una raíz de sombra, siempre y cuando la regla de at @keyframes
esté en un alcance ancestral. En la práctica, ningún navegador implementa este comportamiento, y solo se puede hacer referencia a las definiciones de fotogramas clave en el alcance en el que se definen. Consulta el problema 10540.
@property
Como se define en la especificación, cualquier declaración de @property
se aplanará al alcance del documento. Sin embargo, en la actualidad, en todos los navegadores, solo puedes declarar @property
en el alcance del documento, y se ignoran las declaraciones de @property
dentro de las raíces de sombra.
Consulta el problema 10541.
Errores específicos del navegador
Las otras funciones no muestran un comportamiento coherente en todos los navegadores:
@font-face
se aplana al alcance raíz en Safari.- Chromium no permite heredar reglas
anchor-name
en un elemento raíz en sombra. scroll-timeline-name
yview-timeline-name
no tienen el alcance correcto en::part
(también en Chromium).- Ningún navegador permite declarar
@font-palette-values
en una raíz de sombra. view-transition-class
se puede definir dentro de una raíz de sombra (la transición en sí está fuera de la raíz de sombra).- Firefox permite que
::part
acceda a los nombres de sombras internas (consultas de contenedores, fotogramas clave). - Firefox y Safari no respetan
@counter-style
en un elemento raíz en sombra.
Ten en cuenta que counter-reset
, counter-set
y counter-increment
tienen reglas ligeramente diferentes porque son nombres implícitos, y declarar propiedades CSS tiene un conjunto de reglas establecido y bien probado.
Conclusión
La mala noticia es que, cuando se examina el resumen del estado de interoperabilidad actual con respecto a los nombres de CSS y el DOM sombreado, la experiencia es incoherente y con errores. Ninguna de las funciones que examinamos aquí se comporta de manera coherente en todos los navegadores y según las especificaciones. La buena noticia es que la diferencia para que la experiencia sea coherente es una lista finita de errores y problemas de especificación. Solucionemos esto. Mientras tanto, esperamos que esta sinopsis te ayude si tienes problemas con las inconsistencias que se describen en este artículo.