O polyfill do ShadyCSS não está manipulando CSS corretamente no Edge

8

Estou criando um widget para sites de terceiros, usando o DOM DOM para impedir que o CSS deles interfira no nosso. Estou usando os polyfills ShadyDOM e ShadyCSS para fazê-lo funcionar no Edge e no IE, mas ele não está transformando o CSS para o DOM da sombra, como seria de esperar.

Exemplo:

<!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>

No Chrome (que suporta sombra DOM nativamente), a stuffdiv tem um plano de fundo rosa, como eu esperaria. Mas no Edge (que não oferece suporte nativo ao shadow DOM), vejo o texto "coisas dentro do shadow dom" (ou seja, meu script foi executado e as funções do ShadyDOM funcionaram), mas não vejo o fundo rosa.

Por que isso está acontecendo? Estou anexando uma raiz de sombra a uma div antiga simples, em vez de usar elementos personalizados, como o exemplo no README do ShadyCSS, mas isso importa? Se sim, como posso fazer isso funcionar? Estou trabalhando em um aplicativo grande e existente, e não quero fazer muitas alterações de uma só vez; portanto , prefiro usar os elementos HTML padrão que já estou usando ( divs, buttons, etc.) em vez de criar o meu próprios elementos ou modelos , embora eu esteja disposto a considerar modelos e / ou elementos personalizados, se isso puder ser feito facilmente, sem ter que fazer muitas grandes mudanças.

Elias Zamaria
fonte
Eu tentei várias coisas, como anexar o styleelemento diretamente à divraiz interna, em vez da raiz da sombra, anexar o styleelemento depois de anexar o interno dive definir innerHTMLo styleelemento depois de anexá-lo. Mas nada disso ajudou.
Elias Zamaria
Se eu remover o :hostseletor de CSS, os estilos serão aplicados. Mas eles também são aplicados a coisas fora da raiz das sombras, o que eu não quero.
Elias Zamaria
Eu também tentei coisas como ShadyCSS.styleElement(element)e ShadyCSS. styleSubtree(element)e eles não funcionou.
Elias Zamaria
Consegui fazer com que o polyfill estilizasse um elemento personalizado feito com um modelo, mas gostaria de evitar isso, porque fazer isso no meu aplicativo exigiria alterações e novas pesquisas em várias coisas.
Elias Zamaria
Caso isso seja útil para qualquer pessoa: meu aplicativo usa Preact. Estou usando um componente de ordem superior para isolar nosso CSS do CSS de terceiros (que, de outra forma, interfeririam no nosso CSS de várias maneiras). Funciona colocando nossas coisas em iframes e fazendo alguns truques para colocar as styletags no lugar certo e ajustar as dimensões adequadamente. É lento na renderização e complicado de lidar, então eu mudei para usar o DOM DOM. Agora, ele funciona perfeitamente em todos os navegadores que não são da Microsoft. Estou tentando fazê-lo funcionar no Edge e no IE usando o polyfill, mas não está funcionando.
Elias Zamaria

Respostas:

7

Com ShadyCSS

:host O pseudoelemento CSS não é conhecido no Edge.

Para fazê-lo funcionar, você deve usar ShadyCSS.prepareTemplate()que substituirá: host pelo nome do elemento personalizado e defina o estilo como um estilo global que será aplicado a toda a página.

Lembre-se de que não há Shadow DOM no Edge: não há limites / escopo para CSS com um Shadow DOM falso / polifilmado.

No seu caso, você pode usar ShadyCSS.prepareTemplate( yourTemplate, 'div' )como no exemplo abaixo:

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: como o polyfill substituirá: host por div e o adicionará como um estilo global, você poderá observar alguns efeitos colaterais se tiver outra parte do código HTML que corresponda div .stuff.


Sem ShadyCSS

O ShadyCSS foi projetado para elementos personalizados, mas não para elementos padrão. No entanto, você deve se inspirar no polyfill e criar explicitamente as propriedades de estilo para o Shadow DOM falso (polyfilled). No seu caso, substitua :hostpor 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
fonte
Obrigado pela resposta. Estou ocupado tentando minhas próprias idéias. Vou experimentar a sua e considerarei aceitar ou aprovar sua resposta quando tiver uma chance, que provavelmente será em breve amanhã.
Elias Zamaria
Esta resposta me ajudou muito obrigado!
Calypop #
Parece bom, mas algum desses itens de modelo pode ser (fácil e realisticamente) feito para funcionar em um aplicativo Preact (ou React) que constantemente tenta alterar o conteúdo dos divs (em vários momentos, por vários motivos)? Eu precisaria fazê-lo de alguma forma alterar o DOM da sombra no momento certo, certo?
Elias Zamaria
@EliasZamaria desculpe, eu não sou especialista em React, mas sei que alguns o usam com o Shadow DOM (por exemplo, github.com/Wildhoney/ReactShadow ). Dependendo do seu caso de uso, talvez você precise usar o MutationObserver para detectar alterações no DOM.
Supersharp
@ Supersharp obrigado pela sua resposta. Os observadores de mutação parecem legais, mas acho que não vale a pena usá-los para o meu caso de uso (emulando o DOM de sombra o suficiente para os 8% dos usuários que usam o Edge e o IE).
Elias Zamaria