Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. HTML & CSS

Einführung in Shadow DOM

by
Difficulty:BeginnerLength:LongLanguages:

German (Deutsch) translation by Tatsiana Bochkareva (you can also view the original English article)

Nehmen Sie eine moderne Webseite und Sie bemerken, dass sie ausnahmslos einen Content hat, die aus verschiedenen Quellen zusammengefügt wurden. Es kann die Social-Sharing-Widgets von Twitter oder Facebook oder ein Youtube Video-Wiedergabe-Widget enthalten, es kann eine personalisierte Werbung von einem Ad-Server liefern oder es kann einige Hilfsskripte oder -stile aus einer über CDN gehosteten Drittanbieter-Bibliothek usw. enthalten. Und wenn alles HTML-basiert ist (wie es heutzutage bevorzugt wird), besteht eine hohe Wahrscheinlichkeit von Kollisionen zwischen Markups, Skripten oder Stilen, die aus verschiedenen Quellen bereitgestellt werden. Im Allgemeinen werden Namespaces verwendet, um diese Kollisionen zu verhindern, die das Problem bis zu einem gewissen Grad lösen. Sie bieten jedoch keine Kapselung.

Die Kapselung ist eine der Säulen, auf denen das Paradigma der objektorientierten Programmierung basiert, und wird normalerweise verwendet, um die interne Repräsentation eines Objekts von außen einzuschränken.

Wenn wir auf unser Problem zurückkommen, können wir den JavaScript-Code sicherlich mithilfe von Abschlüssen oder mithilfe des Modulmusters kapseln. Können wir dies jedoch auch für unser HTML-Markup tun? Stellen Sie sich vor, wir müssen ein UI-Widget erstellen. Können wir die Implementierungsdetails unseres Widgets vor dem JavaScript- und CSS-Code verbergen, der auf der Seite enthalten ist, die unser Widget verwendet? Können wir alternativ verhindern, dass der konsumierende Code die Funktionalität oder das Erscheinungsbild unseres Widgets beeinträchtigt?


Shadow DOM zur Rettung

Die einzige existierende Lösung, die eine Grenze zwischen dem von Ihnen geschriebenen Code und dem verbrauchenden Code schafft, ist hässlich - und verwendet einen sperrigen und restriktiven iFrame, der weitere Probleme mit sich bringt. Sind wir also gezwungen, uns immer an diesen Ansatz anzupassen?

Nicht länger! Shadow DOM bietet uns eine elegante Möglichkeit, den normalen DOM-Teilbaum mit einem speziellen Dokumentfragment zu überlagern, das einen weiteren Teilbaum von Knoten enthält, die für Skripte und Stile uneinnehmbar sind. Das Interessante ist, dass es nichts Neues ist! Verschiedene Browser haben diese Methode bereits verwendet, um native Widgets wie Datum, Schieberegler, Audio-, Videoplayer usw. zu implementieren.

Aktivieren von Shadow DOM

Zum Zeitpunkt dieses Schreibens unterstützt die aktuelle Version von Chrome(v29) die Überprüfung von Shadow DOM mit Chrome DevTools. Öffnen Sie Devtools und klicken Sie auf die Zahnradschaltfläche unten rechts auf dem Bildschirm, um das Einstellungsfenster zu öffnen. Scrollen Sie ein wenig nach unten und Sie sehen ein Kontrollkästchen zum Anzeigen von Shadow DOM.

Turn on Shadow DOM

Nachdem wir unseren Browser aktiviert haben, können Sie die Interna des Standard-Audio-Players überprüfen. Tippen Sie einfach:

In Ihr HTML-Markup. In den unterstützten Browsern wird der folgende native Audio-Player angezeigt:

audio_player

Überprüfen Sie nun das gerade erstellte Audio-Player-Widget.

Shadow DOM of Native Date Widget

Beeindruckend! Es zeigt die interne Darstellung des Audio-Players, die ansonsten ausgeblendet wurde. Wie wir sehen können, verwendet das Audioelement ein Dokumentfragment, um den internen Inhalt des Widgets zu speichern, und hängt diesen an das Containerelement (das als Shadow Host bezeichnet wird) an.

Shadow Host und Shadow Root

  • Shadow Host: ist das DOM-Element, das den Shadow DOM-Teilbaum hostet, oder es ist der DOM-Knoten, der die Shadow Root enthält.
  • Schadow Root: ist Root des DOM-Teilbaums, der die Schatten-DOM-Knoten enthält. Es ist ein spezieller Knoten, der die Grenze zwischen den normalen DOM-Knoten und den Schatten-DOM-Knoten erstellt. Es ist diese Grenze, die die Shadow-DOM-Knoten aus jedem JavaScript- oder CSS-Code auf der konsumierenden Seite kapselt.
  • Shadow DOM: Ermöglicht die Zusammenstellung mehrerer DOM-Teilbäume zu einem größeren Baum. Das Befolgen von Bildern aus dem W3C-Arbeitsentwurf erklärt das Konzept der Überlagerung der Knoten am besten. So sieht es aus, bevor der Inhalt der Schattenwurzel an das Schattenhost-Element angehängt wird:
    Normal Document Tree Shadow DOM Subtrees

    Beim Rendern ersetzt der Shadow Tree den Inhalt des Schattenhosts.

    Composition Complete

    Dieser Prozess der Überlagerung der Knoten wird häufig als Zusammensetzung bezeichnet.

  • Shadow Boundary: Wird im obigen Bild durch die gepunktete Linie gekennzeichnet. Dies bezeichnet die Trennung zwischen der normalen DOM-Welt und der Shadow-DOM-Welt. Die Skripte von beiden Seiten können diese Grenze nicht überschreiten und auf der anderen Seite Chaos verursachen.

Hallo Shadow DOM World

Genug geplaudert Ich sage: Machen wir uns die Hände schmutzig, indem wir Code schreiben. Angenommen, wir haben das folgende Markup, das eine einfache Begrüßungsnachricht anzeigt.

Fügen Sie den folgenden JavaScript-Code hinzu oder verwenden Sie diese Fiddle:

Hier erstellen wir mit der Funktion webkitCreateShadowRoot() ein Shadow Root, hängen es an einen Shadow Host an und ändern dann einfach den Inhalt.

Beachten Sie das herstellerspezifische Präfix-webkit vor dem Funktionsnamen. Dies zeigt an, dass diese Funktionalität derzeit nur in einigen Webkit-basierten Browsern unterstützt wird.

Wenn Sie dieses Beispiel in einem unterstützten Browser ausführen, wird "Hallo Schatten-DOM-Welt" anstelle von "Willkommen in meiner Welt" angezeigt, da die Schatten-DOM-Knoten die normalen Knoten überschattet haben.

Haftungsausschluss: Wie einige von Ihnen vielleicht bemerken, mischen wir das Markup mit Skripten, was im Allgemeinen nicht empfohlen wird und Shadow DOM keine Ausnahme darstellt. Wir haben bewusst darauf verzichtet, Vorlagen so früh im Spiel zu verwenden, um Verwirrung zu vermeiden. Andernfalls bietet Shadow DOM eine elegante Lösung für dieses Problem, und wir werden es bald erreichen.


Schattengrenze respektieren

Wenn Sie versuchen, mit JavaScript auf den Inhalt des gerenderten Baums zuzugreifen, gehen Sie wie folgt vor:

Sie erhalten den ursprünglichen Inhalt "Willkommen in meiner Welt" und nicht den Inhalt, der tatsächlich auf der Seite gerendert wird, da der Shadow DOM-Baum aus beliebigen Skripten gekapselt ist. Dies bedeutet auch, dass das Widget, das Sie mit Shadow DOM erstellen, vor unerwünschten / widersprüchlichen Skripten geschützt ist, die bereits auf der Seite vorhanden sind.

Styles-Kapselung

Ebenso ist es jedem CSS-Selektor verboten, die Schattengrenze zu überschreiten. Überprüfen Sie den folgenden Code, in dem wir den Listenelementen rote Farbe zugewiesen haben. Dieser Stil wird jedoch nur auf die Knoten angewendet, die Teil der übergeordneten Seite sind, und die Listenelemente, die Teil von Shadow Root sind, sind von diesem Stil nicht betroffen.

Sie können den Code in Aktion auf Fiddle sehen. Diese Kapselung gilt auch dann, wenn wir die Richtung der Durchquerung umkehren. Alle Stile, die im Shadow DOM definiert sind, wirken sich nicht auf das übergeordnete Dokument aus und bleiben nur für das Shadow Root gültig. In dieser Fiddle finden Sie ein Beispiel, in dem wir die blaue Farbe auf Listenelemente in Shadow DOM anwenden, die Listenelemente des übergeordneten Dokuments jedoch nicht betroffen sind.

Es gibt hier jedoch eine bemerkenswerte Ausnahme; Shadow DOM gibt uns die Flexibilität, den Shadow Host zu formatieren, den DOM-Knoten, der das Shadow DOM enthält. Im Idealfall liegt es außerhalb der Schattengrenze und ist nicht Teil von Shadow Root. Mit der @host-Regel können Sie jedoch die Stile angeben, die auf Shadow Host angewendet werden können, da wir die Begrüßungsnachricht im folgenden Beispiel gestaltet haben.

Überprüfen Sie diese Fiddle, während wir die Begrüßungsnachricht des Shadow Hosts mit den in Shadow DOM definierten Stilen gestalten.

Erstellen von Style-Hooks

Als Widget-Entwickler möchte ich möglicherweise, dass der Benutzer meines Widgets bestimmte Elemente formatieren kann. Dies ist möglich, indem ein Loch mit benutzerdefinierten Pseudoelementen in die Schattengrenze gesteckt wird. Dies ähnelt dem Erstellen von Style-Hooks durch einige Browser, damit der Entwickler einige interne Elemente eines nativen Widgets formatieren kann. Um beispielsweise den Daumen und die Spur des nativen Schiebereglers zu formatieren, können Sie den ::-webkit-slider-thumb und den ::webkit-slider-runnable-track wie folgt verwenden:

Gabel diese Fiddle und wende deine eigenen Stile darauf an!

Event-Re-Targeting

Wenn ein Ereignis, das von einem der Knoten in Shadow DOM stammt, die Shadow Boundary überschreitet, wird erneut auf den Shadow Host verwiesen, um die Kapselung aufrechtzuerhalten. Betrachten Sie den folgenden Code:

Es rendert zwei Texteingabeelemente, eines über das normale DOM und eines über das Schatten-DOM, und wartet dann auf ein click ereignis im document. Wenn Sie nun auf die zweite Texteingabe klicken, stammt das Ereignis aus dem Shadow DOM. Wenn es die Schattengrenze überschreitet, wird das Ereignis so geändert, dass das Zielelement anstelle der Texteingabe <input> in das <div> -Element von Shadow Host geändert wird . Wir haben hier auch ein neues <template> -Element eingeführt. Dies ähnelt konzeptionell clientseitigen Vorlagenlösungen wie Lenker und Unterstrich, ist jedoch nicht so weiterentwickelt und bietet keine Browserunterstützung. Die Verwendung von Vorlagen ist jedoch der ideale Weg, um Shadow DOM zu schreiben, anstatt Skript-Tags zu verwenden, wie dies bisher in diesem Artikel getan wurde.


Trennung von Bedenken

Wir wissen bereits, dass es immer eine gute Idee ist, den tatsächlichen Inhalt von der Präsentation zu trennen. Shadow DOM sollte keine Inhalte einbetten, die dem Benutzer endgültig angezeigt werden sollen. Der Inhalt sollte immer auf der Originalseite vorhanden sein und nicht in der Shadow DOM-Vorlage versteckt sein. Wenn die Komposition erfolgt, sollte dieser Inhalt in geeignete Einfügepunkte projiziert werden, die in der Vorlage des Shadow DOM definiert sind. Lassen Sie uns das Hello World-Beispiel unter Berücksichtigung der obigen Trennung neu schreiben - ein Live-Beispiel finden Sie auf Fiddle.

Beim Rendern der Seite wird der Inhalt des Schattenhosts an die Stelle projiziert, an der das Element <content> angezeigt wird. Dies ist ein sehr vereinfachtes Beispiel, bei dem <content> während der Komposition alles im Shadow Host aufnimmt. Es kann jedoch sehr selektiv sein, den Inhalt von Shadow Host mithilfe des unten gezeigten select-Attributs auszuwählen

Schauen Sie sich die Live-Demo an und spielen Sie damit, um das Konzept der Einfügepunkte und Projektionen besser zu verstehen.


Webkomponenten

Wie Sie vielleicht bereits wissen, ist Shadow DOM Teil der Web Components Spec, die andere nützliche Funktionen bietet, wie zum Beispiel:

  1. Vorlagen - werden verwendet, um inerte Markups zu speichern, die zu einem späteren Zeitpunkt verwendet werden sollen. Mit inert meinen wir, dass nicht alle Bilder im Markup heruntergeladen werden und die enthaltenen Skripte erst vorhanden sind, wenn der Inhalt der Vorlage tatsächlich Teil der Seite wird.
  2. Dekorateure - werden verwendet, um die auf CSS-Selektoren basierenden Vorlagen anzuwenden, und können daher als Dekoration der vorhandenen Elemente angesehen werden, indem ihre Präsentation verbessert wird.
  3. HTML-Importe - bietet uns die Möglichkeit, andere HTML-Dokumente in unserem Dokument wiederzuverwenden, ohne explizit XHR-Aufrufe durchführen und Ereignishandler dafür schreiben zu müssen.
  4. Benutzerdefinierte Elemente - Ermöglicht die Definition neuer HTML-Elementtypen, die dann deklarativ im Markup verwendet werden können. Wenn Sie beispielsweise ein eigenes Navigations-Widget erstellen möchten, definieren Sie Ihr Navigationselement, das von HTMLElement erbt, und stellen bestimmte Lebenszyklus-Rückrufe bereit, die bestimmte Ereignisse wie Aufbau, Änderung, Zerstörung des Widgets implementieren und dieses Widget einfach in Ihrem Markup verwenden als <myAwesomeNavigation attr1="value"..></myAwesomeNavigation> Benutzerdefinierte Elemente geben uns also im Wesentlichen die Möglichkeit, die gesamte Magie von Shadow DOM zu bündeln, die internen Details zu verbergen und alles zusammen zu packen.

Ich werde nicht viel über andere Aspekte der Webkomponenten-Spezifikation in diesem Artikel plappern, aber es würde uns gut tun, daran zu denken, dass sie es uns gemeinsam ermöglichen, wiederverwendbare UI-Widgets zu erstellen, die in Aussehen und Verhalten über Browser hinweg portierbar sind und von allen vollständig gekapselt werden Skripte und Stile der konsumierenden Seite.


Abschluss

Die Webkomponenten-Spezifikation ist in Arbeit und der enthaltene Beispielcode, der heute funktioniert, funktioniert möglicherweise nicht in einer späteren Version. In früheren Texten zu diesem Thema wird beispielsweise die webkitShadowRoot() -Methode verwendet, die nicht mehr funktioniert. Verwenden Sie stattdessen createWebkitShadowRoot(), um eine Schattenwurzel zu erstellen. Wenn Sie dies verwenden möchten, um einige coole Demos mit Shadow DOM zu erstellen, ist es immer am besten, sich für Einzelheiten auf die Spezifikation zu beziehen.

Derzeit wird es nur von Chrome und Opera unterstützt, daher wäre ich vorsichtig, wenn ich Shadow DOM in meine Produktionsinstanz aufnehmen würde. Da Google jedoch Polymer herausbringt, das auf Webkomponenten und Polyfills basiert, die Shadow DOM nativ unterstützen, ist dies der Fall sicherlich etwas, mit dem sich jeder Webentwickler die Hände schmutzig machen muss.

Sie können auch über die neuesten Ereignisse in Shadow DOM auf dem Laufenden bleiben, indem Sie diesem Google+ Kanal folgen. Schauen Sie sich auch das Shadow DOM Visualizer-Tool an, mit dem Sie visualisieren können, wie Shadow DOM im Browser gerendert wird.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.