Houdini: Vielleicht die aufregendste CSS-Entwicklung, von der Sie noch nie gehört haben
Veröffentlicht: 2022-03-10Wollten Sie schon immer eine bestimmte CSS-Funktion verwenden, haben es aber nicht getan, weil sie nicht in allen Browsern vollständig unterstützt wurde ? Oder, schlimmer noch, es wurde in allen Browsern unterstützt, aber die Unterstützung war fehlerhaft, inkonsistent oder sogar völlig inkompatibel? Wenn Ihnen das passiert ist – und ich wette, das ist passiert – dann sollten Sie sich um Houdini kümmern.
Houdini ist eine neue Task Force des W3C, deren ultimatives Ziel es ist, dieses Problem für immer zu beseitigen. Es plant, dies durch die Einführung einer neuen Reihe von APIs zu erreichen, die Entwicklern zum ersten Mal die Möglichkeit geben, CSS selbst zu erweitern, und die Tools, um sich in den Gestaltungs- und Layoutprozess der Rendering-Engine eines Browsers einzuklinken .
Weiterführende Literatur zu SmashingMag:
- Warum Sie aufhören sollten, Ihre WebDev-Umgebung lokal zu installieren
- Die Zukunft von CSS: Experimentelle CSS-Eigenschaften
- 53 CSS-Techniken, ohne die Sie nicht leben könnten
Aber was heißt das konkret? Ist es überhaupt eine gute Idee? Und wie wird es uns Entwicklern helfen, jetzt und in Zukunft Websites zu erstellen?
In diesem Artikel werde ich versuchen, diese Fragen zu beantworten. Aber bevor ich das tue, ist es wichtig, klar zu machen, was die Probleme heute sind und warum es einen solchen Veränderungsbedarf gibt. Ich werde dann genauer darauf eingehen, wie Houdini diese Probleme lösen wird, und einige der aufregenderen Funktionen auflisten, die sich derzeit in der Entwicklung befinden. Abschließend werde ich einige konkrete Dinge anbieten, die wir als Webentwickler heute tun können, um Houdini Wirklichkeit werden zu lassen.
Welche Probleme versucht Houdini zu lösen?
Jedes Mal, wenn ich einen Artikel schreibe oder eine Demo erstelle, die eine brandneue CSS-Funktion zeigt, wird unweigerlich jemand in den Kommentaren oder auf Twitter etwas sagen wie: „Das ist großartig! Schade, dass wir es nicht für weitere 10 Jahre verwenden können.“
So nervig und unkonstruktiv solche Kommentare auch sind, ich verstehe die Stimmung. In der Vergangenheit hat es Jahre gedauert, bis Feature-Vorschläge eine breite Akzeptanz gefunden haben. Und der Grund dafür ist, dass in der gesamten Geschichte des Webs der einzige Weg, eine neue Funktion zu CSS hinzuzufügen, darin bestand, den Standardprozess zu durchlaufen.

Obwohl ich absolut nichts gegen den Standardprozess habe, kann ich nicht leugnen, dass es lange dauern kann!
Zum Beispiel wurde Flexbox erstmals 2009 vorgeschlagen, und Entwickler beschweren sich immer noch, dass sie es heute aufgrund mangelnder Browserunterstützung nicht verwenden können. Zugegeben, dieses Problem verschwindet langsam, da fast alle modernen Browser jetzt automatisch aktualisiert werden. aber selbst bei modernen Browsern wird es immer eine Verzögerung zwischen dem Vorschlag und der allgemeinen Verfügbarkeit einer Funktion geben.
Interessanterweise ist dies nicht in allen Bereichen des Webs der Fall. Überlegen Sie, wie die Dinge in letzter Zeit in JavaScript funktioniert haben:

In diesem Szenario kann die Zeit zwischen der Idee und deren Umsetzung in der Produktion manchmal eine Frage von Tagen sein. Ich meine, ich verwende die async
/ await
-Funktionen bereits in der Produktion, und diese Funktion wurde nicht einmal in einem einzigen Browser implementiert!
Sie können auch einen großen Unterschied in den allgemeinen Gefühlen dieser beiden Gemeinschaften erkennen. In der JavaScript-Community liest man Artikel, in denen sich Leute darüber beschweren, dass die Dinge zu schnell gehen. Auf der anderen Seite hört man bei CSS Leute die Sinnlosigkeit beklagen, etwas Neues zu lernen, weil es so lange dauern wird, bis sie es tatsächlich verwenden können.
Also, warum schreiben wir nicht einfach mehr CSS Polyfills?
Auf den ersten Blick scheint es die Lösung zu sein, mehr CSS-Polyfills zu schreiben. Mit guten Polyfills könnte sich CSS so schnell wie JavaScript bewegen, richtig?
Leider ist es nicht so einfach. Polyfilling CSS ist unglaublich schwierig und in den meisten Fällen unmöglich auf eine Weise zu bewerkstelligen, die die Leistung nicht vollständig zerstört.
JavaScript ist eine dynamische Sprache, was bedeutet, dass Sie JavaScript verwenden können, um JavaScript zu füllen. Und weil es so dynamisch ist, ist es extrem erweiterbar. CSS hingegen kann selten zum Polyfill-CSS verwendet werden. In einigen Fällen können Sie CSS in einem Build-Schritt in CSS transpilieren (PostCSS tut dies); aber wenn Sie irgendetwas polyfillen möchten, das von der DOM-Struktur oder dem Layout oder der Position eines Elements abhängt, müssen Sie die Logik Ihres Polyfills clientseitig ausführen.
Leider macht der Browser dies nicht einfach.
Die folgende Tabelle gibt einen grundlegenden Überblick darüber, wie Ihr Browser vom Empfang eines HTML-Dokuments zur Anzeige von Pixeln auf dem Bildschirm übergeht. Die blau eingefärbten Schritte zeigen, wo JavaScript die Macht hat, die Ergebnisse zu kontrollieren:

Das Bild ist ziemlich düster. Als Entwickler haben Sie keine Kontrolle darüber, wie der Browser HTML und CSS analysiert und in das DOM- und CSS-Objektmodell (CSSOM) umwandelt. Sie haben keine Kontrolle über die Kaskade. Sie haben keine Kontrolle darüber, wie der Browser die Elemente im DOM anordnet oder wie er diese Elemente visuell auf dem Bildschirm darstellt. Und Sie haben keine Kontrolle darüber, was der Compositor tut.
Der einzige Teil des Prozesses, auf den Sie vollen Zugriff haben, ist das DOM. Das CSSOM ist etwas offen; Um die Houdini-Website zu zitieren, ist sie jedoch „unterspezifiziert, inkonsistent über Browser hinweg und es fehlen wichtige Funktionen“.
Das CSSOM in Browsern zeigt Ihnen heute beispielsweise keine Regeln für Cross-Origin-Stylesheets an und verwirft einfach alle CSS-Regeln oder Deklarationen, die es nicht versteht, was bedeutet, dass Sie ein Feature in einem Browser polyfillen möchten das es nicht unterstützt, können Sie das CSSOM nicht verwenden. Stattdessen müssen Sie das DOM durchgehen, die <style>
- und/oder <link rel=“stylesheet”>
-Tags finden, das CSS selbst besorgen, es parsen, umschreiben und dann wieder dem DOM hinzufügen.
Das Aktualisieren des DOM bedeutet natürlich in der Regel, dass der Browser dann die gesamten Cascade-, Layout-, Paint- und Composite-Schritte noch einmal durchlaufen muss.

Auch wenn das vollständige erneute Rendern einer Seite nicht unbedingt ein großer Leistungseinbruch zu sein scheint (insbesondere für einige Websites), sollten Sie bedenken, wie oft dies möglicherweise passieren muss. Wenn die Logik Ihres Polyfills als Reaktion auf Dinge wie Scroll-Ereignisse, Fenstergrößenänderungen, Mausbewegungen, Tastaturereignisse – wirklich immer, wenn sich irgendetwas ändert – ausgeführt werden muss, dann werden die Dinge merklich, manchmal sogar lähmend, langsam sein.
Das wird noch schlimmer, wenn man bedenkt, dass die meisten CSS-Polyfills, die es heute gibt, ihren eigenen CSS-Parser und ihre eigene Kaskadenlogik enthalten. Und weil das Parsen und die Kaskade eigentlich sehr komplizierte Dinge sind, sind diese Polyfills normalerweise entweder viel zu groß oder viel zu fehlerhaft.
Um alles, was ich gerade gesagt habe, kurz zusammenzufassen: Wenn Sie möchten, dass der Browser etwas anderes tut, als er denkt (angesichts des CSS, das Sie ihm gegeben haben), dann müssen Sie einen Weg finden, es durch Aktualisieren und Modifizieren vorzutäuschen das DOM selbst. Sie haben keinen Zugriff auf die anderen Schritte in der Rendering-Pipeline.
Aber warum sollte ich jemals die interne Rendering-Engine des Browsers ändern wollen?
Das ist für mich absolut die wichtigste Frage, die es in diesem ganzen Artikel zu beantworten gilt. Also, wenn Sie die Dinge bisher überflogen haben, lesen Sie diesen Teil langsam und sorgfältig!
Nachdem ich mir den letzten Abschnitt angeschaut habe, bin ich mir sicher, dass einige von Ihnen gedacht haben: „Das brauche ich nicht! Ich baue nur normale Webseiten. Ich versuche nicht, mich in die Interna des Browsers zu hacken oder etwas superschickes, experimentelles oder hochmodernes zu bauen.“
Wenn Sie das denken, dann rate ich Ihnen dringend, für eine Sekunde einen Schritt zurückzutreten und die Technologien, die Sie im Laufe der Jahre zum Erstellen von Websites verwendet haben, wirklich zu untersuchen. Zugriff und Hooks in den Gestaltungsprozess des Browsers zu wollen, bedeutet nicht nur, ausgefallene Demos zu erstellen – es geht darum, Entwicklern und Framework-Autoren die Möglichkeit zu geben, zwei grundlegende Dinge zu tun:
- Browserübergreifende Unterschiede zu normalisieren,
- neue Funktionen zu erfinden oder auszufüllen, damit die Menschen sie heute nutzen können.
Wenn Sie jemals eine JavaScript-Bibliothek wie jQuery verwendet haben, haben Sie bereits von dieser Fähigkeit profitiert! Tatsächlich ist dies heute eines der Hauptverkaufsargumente fast aller Frontend-Bibliotheken und -Frameworks. Die fünf beliebtesten JavaScript- und DOM-Repositories auf GitHub – AngularJS, D3, jQuery, React und Ember – leisten alle viel Arbeit, um browserübergreifende Unterschiede zu normalisieren, sodass Sie nicht darüber nachdenken müssen. Jeder macht eine einzelne API verfügbar, und es funktioniert einfach.
Denken Sie jetzt an CSS und all seine Cross-Browser-Probleme. Sogar beliebte CSS-Frameworks wie Bootstrap und Foundation, die Cross-Browser-Kompatibilität beanspruchen, normalisieren Cross-Browser-Bugs nicht wirklich – sie vermeiden sie nur. Und Cross-Browser-Bugs in CSS gehören nicht nur der Vergangenheit an. Auch heute sind wir mit neuen Layoutmodulen wie Flexbox mit vielen browserübergreifenden Inkompatibilitäten konfrontiert.
Das Fazit ist, stellen Sie sich vor, wie viel schöner Ihr Entwicklungsleben wäre, wenn Sie jede beliebige CSS-Eigenschaft verwenden könnten und sicher wären, dass sie in jedem Browser genau gleich funktionieren würde. Und denken Sie an all die neuen Funktionen, von denen Sie in Blogbeiträgen gelesen oder auf Konferenzen und Treffen gehört haben – Dinge wie CSS-Grids, CSS-Snap-Points und Sticky-Positionierung. Stellen Sie sich vor, Sie könnten sie alle heute und auf eine Weise nutzen, die so leistungsfähig ist wie native CSS-Funktionen. Und alles, was Sie tun müssen, ist den Code von GitHub zu holen.

Das ist der Traum von Houdini. Das ist die Zukunft, die die Task Force zu ermöglichen versucht.
Selbst wenn Sie also nie vorhaben, ein CSS-Polyfill zu schreiben oder eine experimentelle Funktion zu entwickeln, möchten Sie wahrscheinlich, dass andere Leute dies tun können – denn sobald diese Polyfills existieren, profitieren alle davon.
Welche Houdini-Funktionen befinden sich derzeit in der Entwicklung?
Ich habe oben erwähnt, dass Entwickler nur sehr wenige Zugangspunkte zur Rendering-Pipeline des Browsers haben. Wirklich, die einzigen Orte sind das DOM und teilweise das CSSOM.
Um dieses Problem zu lösen, hat die Houdini-Task Force mehrere neue Spezifikationen eingeführt, die Entwicklern zum ersten Mal Zugriff auf die anderen Teile der Rendering-Pipeline geben. Das folgende Diagramm zeigt die Pipeline und welche neuen Spezifikationen verwendet werden können, um welche Schritte zu ändern. (Beachten Sie, dass die Spezifikationen in Grau geplant sind, aber noch geschrieben werden müssen.)

Die nächsten Abschnitte geben einen kurzen Überblick über jede neue Spezifikation und welche Möglichkeiten sie bietet. Ich sollte auch beachten, dass andere Spezifikationen in diesem Artikel nicht erwähnt werden; Die vollständige Liste finden Sie im GitHub-Repository von Houdinis Entwürfen.
CSS-Parser-API
Die CSS-Parser-API ist derzeit nicht geschrieben; Vieles von dem, was ich sage, könnte sich also leicht ändern, aber die Grundidee ist, dass es Entwicklern ermöglicht, den CSS-Parser zu erweitern und ihn über neue Konstrukte zu informieren – zum Beispiel neue Medienregeln, neue Pseudoklassen, Verschachtelung, @extends
, @apply
usw.
Sobald der Parser diese neuen Konstrukte kennt, kann er sie an der richtigen Stelle im CSSOM platzieren, anstatt sie einfach zu verwerfen.
API für CSS-Eigenschaften und -Werte
CSS hat bereits benutzerdefinierte Eigenschaften, und wie ich bereits gesagt habe, bin ich sehr gespannt auf die Möglichkeiten, die sie eröffnen. Die API für CSS-Eigenschaften und -Werte geht noch einen Schritt weiter und macht sie durch das Hinzufügen von Typen noch nützlicher.
Es gibt viele tolle Dinge beim Hinzufügen von Typen zu benutzerdefinierten Eigenschaften, aber das vielleicht größte Verkaufsargument ist, dass Typen es Entwicklern ermöglichen, benutzerdefinierte Eigenschaften zu überführen und zu animieren, was wir heute nicht tun können.
Betrachten Sie dieses Beispiel:
body { --primary-theme-color: tomato; transition: --primary-theme-color 1s ease-in-out; } body.night-theme { --primary-theme-color: darkred; }
Wenn im obigen Code die night-theme
Klasse zum <body>
-Element hinzugefügt wird, wechselt jedes einzelne Element auf der Seite, das auf den Eigenschaftswert –primary-theme-color
verweist, langsam von tomato
zu darkred
. Wenn Sie dies heute tun wollten, müssten Sie den Übergang für jedes dieser Elemente manuell schreiben, da Sie die Eigenschaft selbst nicht überführen können.
Ein weiteres vielversprechendes Feature dieser API ist die Möglichkeit, einen „Apply-Hook“ zu registrieren, der Entwicklern die Möglichkeit gibt, den endgültigen Wert einer benutzerdefinierten Eigenschaft für Elemente zu ändern, nachdem der Kaskadenschritt abgeschlossen ist, was eine sehr nützliche Funktion für Polyfills sein könnte.
CSS-typisiertes OM
CSS Typed OM kann als Version 2 des aktuellen CSSOM betrachtet werden. Sein Ziel ist es, viele der Probleme mit dem aktuellen Modell zu lösen und Funktionen einzubeziehen, die von der neuen CSS-Parsing-API und der CSS-Eigenschaften- und -Werte-API hinzugefügt wurden.
Ein weiteres wichtiges Ziel von Typed OM ist die Verbesserung der Leistung. Das Konvertieren der Zeichenfolgenwerte des aktuellen CSSOM in sinnvoll typisierte JavaScript-Darstellungen würde zu erheblichen Leistungssteigerungen führen.
CSS-Layout-API
Die CSS-Layout-API ermöglicht es Entwicklern, ihre eigenen Layout-Module zu schreiben. Und mit „Layoutmodul“ meine ich alles, was an die CSS- display
übergeben werden kann. Dies gibt Entwicklern zum ersten Mal eine Möglichkeit zum Layouten, die so leistungsfähig ist wie native Layoutmodule wie display: flex
und display: table
.
Als beispielhafter Anwendungsfall zeigt die Masonry-Layoutbibliothek, wie weit Entwickler heute bereit sind, zu gehen, um komplexe Layouts zu erreichen, die mit CSS allein nicht möglich sind. Obwohl diese Layouts beeindruckend sind, leiden sie leider unter Leistungsproblemen, insbesondere auf weniger leistungsstarken Geräten.
Die CSS-Layout-API funktioniert, indem sie Entwicklern eine registerLayout
-Methode zur Verfügung stellt, die einen Layoutnamen (der später in CSS verwendet wird) und eine JavaScript-Klasse akzeptiert, die die gesamte Layoutlogik enthält. Hier ist ein einfaches Beispiel dafür, wie Sie masonry
über registerLayout
definieren könnten:
registerLayout('masonry', class { static get inputProperties() { return ['width', 'height'] } static get childrenInputProperties() { return ['x', 'y', 'position'] } layout(children, constraintSpace, styleMap, breakToken) { // Layout logic goes here. } }
Wenn nichts im obigen Beispiel für Sie sinnvoll ist, machen Sie sich keine Sorgen. Das Wichtigste, worauf Sie achten sollten, ist der Code im nächsten Beispiel. Sobald Sie die Datei masonry.js
heruntergeladen und zu Ihrer Website hinzugefügt haben, können Sie CSS wie folgt schreiben und alles wird einfach funktionieren:
body { display: layout('masonry'); }
CSS-Paint-API
Die CSS-Paint-API ist der obigen Layout-API sehr ähnlich. Es stellt eine registerPaint
-Methode bereit, die genau wie die registerLayout
-Methode funktioniert. Entwickler können dann die Funktion paint()
in CSS überall dort verwenden, wo ein CSS-Bild erwartet wird, und den registrierten Namen übergeben.
Hier ist ein einfaches Beispiel, das einen farbigen Kreis malt:
registerPaint('circle', class { static get inputProperties() { return ['--circle-color']; } paint(ctx, geom, properties) { // Change the fill color. const color = properties.get('--circle-color'); ctx.fillStyle = color; // Determine the center point and radius. const x = geom.width / 2; const y = geom.height / 2; const radius = Math.min(x, y); // Draw the circle \o/ ctx.beginPath(); ctx.arc(x, y, radius, 0, 2 * Math.PI, false); ctx.fill(); } });
Und es kann in CSS so verwendet werden:
.bubble { --circle-color: blue; background-image: paint('circle'); }
Jetzt wird das .bubble
Element mit einem blauen Kreis als Hintergrund angezeigt. Der Kreis wird zentriert und hat die gleiche Größe wie das Element selbst, was auch immer das sein mag.
Worklets
Viele der oben aufgeführten Spezifikationen zeigen Codebeispiele (z. B. registerLayout
und registerPaint
). Wenn Sie sich fragen, wo Sie diesen Code ablegen würden, finden Sie die Antwort in Worklet-Skripten.
Worklets ähneln Webworkern und ermöglichen es Ihnen, Skriptdateien zu importieren und JavaScript-Code auszuführen, der (1) an verschiedenen Stellen in der Rendering-Pipeline aufgerufen werden kann und (2) unabhängig vom Haupt-Thread ist.
Worklet-Skripte schränken die Arten von Vorgängen, die Sie ausführen können, stark ein, was der Schlüssel zur Gewährleistung einer hohen Leistung ist.
Zusammengesetztes Scrollen und Animation
Obwohl es noch keine offizielle Spezifikation für zusammengesetztes Scrollen und Animationen gibt, ist es tatsächlich eines der bekannteren und mit Spannung erwarteten Houdini-Features. Die eventuellen APIs werden es Entwicklern ermöglichen, Logik in einem Compositor-Worklet außerhalb des Haupt-Threads auszuführen, mit Unterstützung für die Änderung einer begrenzten Teilmenge der Eigenschaften eines DOM-Elements. Diese Teilmenge enthält nur Eigenschaften, die gelesen oder festgelegt werden können, ohne dass die Rendering-Engine das Layout oder den Stil neu berechnen muss (z. B. Transformation, Deckkraft, Scroll-Offset).
Dadurch können Entwickler hochleistungsfähige scroll- und eingabebasierte Animationen wie Sticky-Scroll-Header und Parallax-Effekte erstellen. Auf GitHub können Sie mehr über die Anwendungsfälle lesen, die diese APIs zu lösen versuchen.
Obwohl es noch keine offizielle Spezifikation gibt, hat die experimentelle Entwicklung in Chrome bereits begonnen. Tatsächlich implementiert das Chrome-Team derzeit CSS-Snap-Points und Sticky-Positionierung unter Verwendung der Primitive, die diese APIs schließlich verfügbar machen werden. Das ist erstaunlich, denn es bedeutet, dass Houdini-APIs leistungsfähig genug sind, dass neue Chrome-Funktionen darauf aufbauen. Wenn Sie immer noch Befürchtungen hatten, dass Houdini nicht so schnell wie einheimisch sein würde, sollte Sie allein diese Tatsache vom Gegenteil überzeugen.
Um ein echtes Beispiel zu sehen, hat Surma eine Videodemo aufgezeichnet, die auf einem internen Build von Chrome ausgeführt wird. Die Demo ahmt das Verhalten des Scroll-Headers nach, das in den nativen mobilen Apps von Twitter zu sehen ist. Um zu sehen, wie es funktioniert, sehen Sie sich den Quellcode an.
Was können Sie jetzt tun?
Wie bereits erwähnt, denke ich, dass sich jeder, der Websites erstellt, um Houdini kümmern sollte; es wird unser aller Leben in Zukunft viel einfacher machen. Selbst wenn Sie niemals eine Houdini-Spezifikation direkt verwenden, werden Sie mit ziemlicher Sicherheit etwas verwenden, das auf einer solchen aufbaut.
Und obwohl diese Zukunft vielleicht nicht unmittelbar ist, ist sie wahrscheinlich näher, als viele von uns denken. Vertreter aller großen Browser-Anbieter nahmen Anfang des Jahres am letzten persönlichen Houdini-Meeting in Sydney teil, und es gab kaum Meinungsverschiedenheiten darüber, was gebaut oder wie vorgegangen werden soll.
Soweit ich das beurteilen konnte, ist es keine Frage, ob Houdini ein Ding sein wird, sondern wann, und da kommen Sie alle ins Spiel.
Browserhersteller müssen, wie alle anderen, die Software entwickeln, neue Funktionen priorisieren. Und diese Priorität hängt oft davon ab, wie sehr Benutzer diese Funktionen wollen.
Wenn Ihnen also die Erweiterbarkeit von Design und Layout im Web wichtig ist und Sie in einer Welt leben möchten, in der Sie neue CSS-Funktionen verwenden können, ohne darauf warten zu müssen, dass sie den Standardprozess durchlaufen, sprechen Sie mit Mitgliedern des Developer Relations Teams für die von Ihnen verwendeten Browser und teilen Sie ihnen mit, dass Sie dies wünschen.
Die andere Möglichkeit, wie Sie helfen können, besteht darin, reale Anwendungsfälle bereitzustellen – Dinge, die Sie mit Styling und Layout tun können möchten, die heute schwierig oder unmöglich sind. Einige der Entwürfe auf GitHub enthalten Anwendungsfalldokumente, und Sie können eine Pull-Anfrage einreichen, um Ihre Ideen beizusteuern. Wenn kein Dokument vorhanden ist, können Sie eines erstellen.
Mitglieder der Houdini-Task Force (und des W3C im Allgemeinen) wollen wirklich durchdachten Input von Webentwicklern. Die meisten Personen, die am Prozess zum Schreiben von Spezifikationen teilnehmen, sind Ingenieure, die an Browsern arbeiten. Sie sind oft selbst keine professionellen Webentwickler und wissen daher nicht immer, wo die Schwachstellen liegen.
Sie sind darauf angewiesen, dass wir es ihnen sagen.
Ressourcen und Links
- CSS-TAG Houdini Editor Drafts, W3C Die neueste öffentliche Version aller Houdini-Entwürfe
- CSS-TAG Houdini Task Force Specifications, GitHub Das offizielle Github-Repository, in dem Spezifikationsaktualisierungen und -entwicklungen stattfinden
- Houdini Samples, GitHub Codebeispiele, die mögliche APIs präsentieren und damit experimentieren
- Houdini-Mailingliste, W3C Ein Ort, an dem Sie allgemeine Fragen stellen können
Besonderer Dank gilt den Houdini-Mitgliedern Ian Kilpatrick und Shane Stephens für die Durchsicht dieses Artikels.