El polyfill de ShadyCSS no maneja correctamente CSS en Edge

8

Estoy creando un widget para sitios web de terceros, usando shadow DOM para evitar que su CSS interfiera con el nuestro. Estoy usando los polyfills ShadyDOM y ShadyCSS para que funcione en Edge e IE, pero no está transformando el CSS para el DOM de sombra como era de esperar.

Ejemplo:

<!DOCTYPE html>
<html>
	<head>
		<title>Shadow DOM test</title>
	</head>
	<body>
		<div id="container">container is here</div>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.3.0/webcomponents-bundle.js"></script>
		<script>
			const shadow = document.getElementById("container").attachShadow({ mode: "open" });
			const style = document.createElement("style");
			style.innerHTML = `
				:host .stuff {
					background: #ff00ff;
				}
			`;
			shadow.appendChild(style);
			const div = document.createElement("div");
			div.classList.add("stuff");
			div.innerHTML = "stuff inside shadow dom";
			shadow.appendChild(div);
		</script>
	</body>
</html>

En Chrome (que admite shadow DOM de forma nativa), el stuffdiv tiene un fondo rosa, como era de esperar. Pero en Edge (que no es compatible con shadow DOM de forma nativa), veo el texto "cosas dentro de shadow dom" (lo que significa que mi script se ejecutó y las funciones ShadyDOM funcionaron), pero no veo el fondo rosa.

¿Por qué está pasando esto? Estoy adjuntando una raíz de sombra a un viejo div simple, en lugar de usar elementos personalizados como lo hace el ejemplo en ShadyCSS README, pero ¿eso importa? Si es así, ¿cómo puedo hacer que esto funcione? Estoy trabajando en una aplicación grande y existente, y no quiero hacer demasiados cambios a la vez, por lo que preferiría usar los elementos HTML estándar que ya estoy usando ( divs, buttons, etc.) en lugar de crear mi propios elementos o plantillas , aunque estaría dispuesto a considerar plantillas y / o elementos personalizados si se puede hacer fácilmente, sin tener que hacer muchos cambios importantes.

Elias Zamaria
fuente
He intentado varias cosas, como agregar el styleelemento directamente al interior en divlugar de la raíz de la sombra, agregar el styleelemento después de agregar el interior divy configurar innerHTMLel styleelemento después de agregarlo. Pero ninguna de esas cosas ayudó.
Elias Zamaria
Si elimino el :hostdel selector CSS, entonces los estilos se aplican. Pero también se aplican a cosas fuera de la raíz de la sombra, que no quiero.
Elias Zamaria
También probé cosas como ShadyCSS.styleElement(element)y ShadyCSS. styleSubtree(element)no funcionaron.
Elias Zamaria
Pude hacer que el polyfill diseñara un elemento personalizado hecho con una plantilla, pero me gustaría evitar hacerlo porque hacer eso en mi aplicación requeriría cambiar y volver a armar un montón de cosas.
Elias Zamaria
En caso de que esto sea útil para cualquiera: mi aplicación usa Preact. Estoy usando un componente de orden superior para aislar nuestro CSS del CSS de terceros (que de lo contrario interferiría con nuestro CSS de muchas maneras). Funciona colocando nuestras cosas en iframes y haciendo algunos trucos para colocar las styleetiquetas en el lugar correcto y ajustar las dimensiones adecuadamente. El procesamiento es lento y engorroso de manejar, por lo que lo cambié para usar DOM de sombra. Ahora funciona perfectamente en todos los navegadores que no son de Microsoft. Estoy tratando de hacerlo funcionar en Edge e IE usando el polyfill, pero no funciona.
Elias Zamaria

Respuestas:

7

Con ShadyCSS

:host El pseudo-elemento CSS no se conoce en Edge.

Para que funcione, debe usar ShadyCSS.prepareTemplate()que reemplazará: host por el nombre del elemento personalizado y definir el estilo como un estilo global que se aplicará a toda la página.

Recuerde que no hay Shadow DOM en Edge: no hay límites / alcance para CSS con un Shadow DOM falso / polifundido.

En su caso, podría usar ShadyCSS.prepareTemplate( yourTemplate, 'div' )como en el siguiente ejemplo:

ShadyCSS.prepareTemplate( tpl, 'div' )
container.attachShadow( { mode: "open" } )
         .appendChild( tpl.content.cloneNode(true) )
<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.3.0/webcomponents-bundle.js"></script>

<template id=tpl>
    <style>
    :host .stuff {
       background: #ff00ff;
     }
     </style>
    <div class=stuff>stuff inside shadow dom</div>
</template>

<div id=container>container is here</div>

Nota: dado que el polyfill reemplazará: host por div y lo agregará como un estilo global, podría observar algunos efectos secundarios si tiene otra parte de código HTML que coincida div .stuff.


Sin ShadyCSS

ShadyCSS fue diseñado para elementos personalizados, pero no realmente para elementos estándar. Sin embargo, debe inspirarse en el polyfill y crear explícitamente las propiedades de estilos para Shadow DOM falso (polyfilled). En su caso, reemplace :hostcon div#containter:

container.attachShadow( { mode: "open" } )
         .appendChild( tpl.content.cloneNode(true) )
<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/2.3.0/webcomponents-bundle.js"></script>

<template id=tpl>
    <style>
    div#container .stuff { 
       background: #ff00ff;
     }    
    :host .stuff {
       background: #ff00ff;
     }
     </style>
    <div class=stuff>stuff inside shadow dom</div>
</template>

<div id=container>container is here</div>

Supersharp
fuente
Gracias por la respuesta. Estoy ocupado probando mis propias ideas. Probaré la suya y consideraré aceptar o votar su respuesta, cuando tenga la oportunidad, que probablemente será en algún momento mañana.
Elias Zamaria
Esta respuesta me ayudó mucho, gracias!
calipoop
Eso se ve bien, pero ¿se puede hacer que cualquiera de esas cosas de plantilla (fácil y realista) funcione en una aplicación Preact (o React) que constantemente está tratando de cambiar el contenido de los divs (en varias ocasiones, por varias razones)? Tendría que hacer que de alguna manera mute la sombra DOM en el momento adecuado, ¿verdad?
Elias Zamaria
@EliasZamaria lo siento, no soy especialista en React, pero sé que algunos lo usan con Shadow DOM (es decir, github.com/Wildhoney/ReactShadow ). Dependiendo de su caso de uso, tal vez necesite usar MutationObserver para detectar cambios en el DOM.
Supersharp
@ SuperSharp gracias por tu respuesta. Los observadores de mutaciones se ven geniales, pero no creo que valga la pena usarlos para mi caso de uso (emulando shadow DOM lo suficientemente bien para el 8% de nuestros usuarios que usan Edge e IE).
Elias Zamaria