ShadyCSS-Polyfill verarbeitet CSS in Edge nicht richtig

8

Ich erstelle ein Widget für Websites von Drittanbietern und verwende Shadow DOM, um zu verhindern, dass deren CSS unsere stört. Ich verwende die Polyfills ShadyDOM und ShadyCSS , damit es in Edge und IE funktioniert, aber es transformiert das CSS für das Schatten-DOM nicht wie erwartet.

Beispiel:

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

In Chrome (das Schatten-DOM nativ unterstützt) hat das stuffdiv erwartungsgemäß einen rosa Hintergrund. Aber in Edge (das Shadow DOM nicht nativ unterstützt) sehe ich den Text "Zeug im Schattendom" (was bedeutet, dass mein Skript ausgeführt wurde und die ShadyDOM-Funktionen funktionierten), aber ich sehe den rosa Hintergrund nicht.

Warum passiert dies? Ich hänge eine Schattenwurzel an ein einfaches altes div an, anstatt benutzerdefinierte Elemente zu verwenden, wie es das Beispiel in der ShadyCSS README tut, aber spielt das eine Rolle? Wenn ja, wie kann ich das zum Laufen bringen? Ich arbeite an einer großen, vorhandenen App und möchte nicht zu viele Änderungen gleichzeitig vornehmen. Daher würde ich es vorziehen, die Standard-HTML-Elemente zu verwenden, die ich bereits verwende ( divs, buttons usw.), anstatt meine zu entwickeln eigene Elemente oder Vorlagen , obwohl ich bereit wäre, Vorlagen und / oder benutzerdefinierte Elemente in Betracht zu ziehen, wenn dies einfach möglich ist, ohne viele große Änderungen vornehmen zu müssen.

Elias Zamaria
quelle
Ich habe verschiedene Dinge ausprobiert, wie das Anhängen des styleElements direkt an das Innere divanstelle der Schattenwurzel, das Anhängen des styleElements nach dem Anhängen des Inneren divund das Festlegen innerHTMLdes styleElements nach dem Anhängen. Aber keines dieser Dinge half.
Elias Zamaria
Wenn ich das :hostaus dem CSS-Selektor entferne , werden die Stile angewendet. Sie werden aber auch auf Dinge außerhalb der Schattenwurzel angewendet, die ich nicht will.
Elias Zamaria
Ich habe auch Sachen wie ShadyCSS.styleElement(element)und ausprobiert ShadyCSS. styleSubtree(element)und sie haben nicht funktioniert.
Elias Zamaria
Ich konnte die Polyfüllung dazu bringen, ein benutzerdefiniertes Element zu formatieren, das mit einer Vorlage erstellt wurde, aber ich möchte dies vermeiden, da dies in meiner App eine Reihe von Änderungen und Umstrukturierungen erfordern würde.
Elias Zamaria
Falls dies für jemanden nützlich ist: Meine App verwendet Preact. Ich verwende eine Komponente höherer Ordnung, um unser CSS von CSS von Drittanbietern zu isolieren (was sonst unser CSS in vielerlei Hinsicht beeinträchtigen würde). Es funktioniert, indem wir unsere Inhalte in Iframes ablegen und einige Tricks ausführen, um styleTags an der richtigen Stelle zu platzieren und die Abmessungen entsprechend anzupassen. Das Rendern ist langsam und umständlich zu handhaben, daher habe ich es geändert, um Schatten-DOM zu verwenden. Jetzt funktioniert es wunderbar in allen Nicht-Microsoft-Browsern. Ich versuche, es mit der Polyfüllung in Edge und IE zum Laufen zu bringen, aber es funktioniert nicht.
Elias Zamaria

Antworten:

7

Mit ShadyCSS

:host CSS-Pseudoelement ist in Edge nicht bekannt.

Damit es funktioniert, sollten Sie Folgendes verwenden ShadyCSS.prepareTemplate(), um: host durch den Namen des benutzerdefinierten Elements zu ersetzen und den Stil als globalen Stil zu definieren, der für alle Seiten gilt.

Denken Sie daran, dass Edge kein Schatten-DOM enthält: Es gibt keine Grenzen / Bereiche für CSS mit einem gefälschten / polygefüllten Schatten-DOM.

In Ihrem Fall könnten Sie ShadyCSS.prepareTemplate( yourTemplate, 'div' )wie im folgenden Beispiel verwenden:

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>

Hinweis: Da die Polyfüllung: host durch div ersetzt und als globalen Stil hinzufügt, können einige Nebenwirkungen auftreten, wenn Sie einen anderen übereinstimmenden HTML-Codeteil haben div .stuff.


Ohne ShadyCSS

ShadyCSS wurde für benutzerdefinierte Elemente entwickelt, jedoch nicht für Standardelemente. Sie sollten sich jedoch von der Polyfüllung inspirieren lassen und die Stileigenschaften für gefälschte (polygefüllte) Schatten-DOM explizit erstellen. In Ihrem Fall ersetzen Sie :hostdurch 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
quelle
Danke für die Antwort. Ich bin damit beschäftigt, meine eigenen Ideen auszuprobieren. Ich werde es mit deiner versuchen und erwägen, deine Antwort zu akzeptieren oder zu bewerten, wenn ich eine Chance bekomme, die wahrscheinlich morgen irgendwann sein wird.
Elias Zamaria
Diese Antwort hat mir sehr geholfen, danke!
Calipoop
Das sieht gut aus, aber kann eines dieser Vorlagen (einfach und realistisch) in einer Preact- (oder React-) App zum Laufen gebracht werden, die ständig versucht, den Inhalt der Divs zu ändern (zu verschiedenen Zeiten, aus verschiedenen Gründen)? Ich müsste es irgendwie zum richtigen Zeitpunkt dazu bringen, das Schatten-DOM zu mutieren, oder?
Elias Zamaria
@EliasZamaria Entschuldigung, ich bin kein Spezialist für React, aber ich weiß, dass einige es mit Shadow DOM verwenden (dh github.com/Wildhoney/ReactShadow ). Abhängig von Ihrem Anwendungsfall müssen Sie möglicherweise MutationObserver verwenden, um Änderungen im DOM zu erkennen.
Supersharp
@Supersharp danke für deine Antwort. Mutationsbeobachter sehen cool aus, aber ich denke nicht, dass es die Mühe wert ist, sie für meinen Anwendungsfall zu verwenden (Schatten-DOM gut genug zu emulieren, damit etwa 8% unserer Benutzer Edge und IE verwenden).
Elias Zamaria