Was hat es mit H5P und diesem „resizing“ auf sich?

Wenn du jemals Probleme mit H5P hattest und jemand dir erklärt hat, was schiefgelaufen ist, könnte der Begriff „resizing“ verwendet worden sein. Das ist ein Ausdruck, der im Zusammenhang mit verschiedenen Problemen bei H5P auftauchen kann. Warum also nicht versuchen, das ein für alle mal zu erklären – Daumen drücken! 🙂

Warum die Größenänderung wichtig ist

H5P-Inhalte, wie interaktive Quizze, können ihre Größe ändern, wenn du mit ihnen interagierst. Wenn du zum Beispiel bei einer Multiple-Choice-Frage auf „Überprüfen“ klickst, wird der Inhalt vergrößert, um am unteren Rand Feedback anzuzeigen. Normalerweise handhaben Webbrowser diese Größenänderung automatisch, indem sie dem Inhalt mehr Platz geben.

Die meisten H5P-Inhalte befinden sich jedoch in einem „iframe“, der wie ein separates Fenster innerhalb deiner Webseite ist. Stell dir deine Webseite wie einen Umschlag vor, den Iframe wie ein Fenster und den H5P-Inhalt wie einen Brief innerhalb des Umschlags. Damit endet die Analogie im Grunde, aber ich mag sie sehr, um Iframes zu erklären.

Der springende Punkt ist, dass die Webseite und der H5P-Inhalt innerhalb des iframes in unterschiedlichen Kontexten existieren. Sie wissen nichts voneinander, und ohne weiteres kommunizieren sie auch nicht miteinander.

Die Herausforderung beim „Resizing“

Wenn du auf den Button „Überprüfen“ klickst, ändert sich die Höhe des Inhalts, aber der iframe merkt das nicht. Er ist Teil der übergeordneten Seite und erkennt nicht, dass sich die Größe des Inhalts ändert. Wir brauchen also eine Möglichkeit, die Größe des iframes zu ändern.

Der H5P-Inhalt kann die Größe des iframes nicht direkt ändern, da er auf seinen Kontext beschränkt ist. Stattdessen schickt er eine Nachricht an den H5P-Kern, die lautet: „Ich habe meine Größe geändert, lass es andere wissen.“ Der H5P-Kern macht das über eine Methode namens „postMessage„, um Nachrichten zwischen verschiedenen Browserkontexten zu senden.

Randnotiz für Entwickler*innen: Ja, man kann dieses Kontextproblem umgehen, wenn die Seite und der Inhalt von derselben Domain aus bereitgestellt werden, aber das wird nicht immer der Fall sein, und H5P hat eine allgemeine Lösung dafür auf Lager.

Ein Teil des JavaScript-Codes, der als „Resizer-Skript“ bezeichnet wird und ebenfalls Teil des H5P-Kerns ist, arbeitet im Kontext der übergeordneten Seite. Das Skript „hört“ auf diese „Resize“-Meldungen, die auch als Ereignisse bezeichnet werden. Wenn es eine solche Nachricht erhält, passt es die Größe des iframes an den Inhalt an. Das funktioniert, weil das Skript zur Größenanpassung und der iframe in demselben Kontext unterwegs sind.

Das ist aber nur ein Teil der Geschichte. Im Grunde passiert das Gleiche, wenn du die Größe des Browserfensters änderst. In diesem Fall sendet dein Browser eine Nachricht, die besagt: „Hey, Leute, ich wurde in der Größe verändert!“ Das Resizer-Skript kann dies „hören“. Es ändert die Größe des iframe nach Bedarf und sendet eine Nachricht an den Teil des H5P-Kerns, der sich innerhalb des iframe befindet. Dieser Teil des H5P-Kerns leitet die Nachricht an den H5P-Inhalt weiter. In einigen Fällen reicht das aus und der Browser erledigt die Arbeit, aber in anderen Fällen muss der H5P-Inhaltstyp bestimmte Dinge neu berechnen. Das ist wirklich von Inhaltstyp zu Inhaltstyp unterschiedlich.

Randnotiz: Trotz des zusätzlichen Aufwands, den iframes erfordern, wurden sie als Schutzmaßnahme gewählt, um zu verhindern, dass das Stylesheet der Seite in das Stylesheet des Inhalts übergeht oder umgekehrt. Iframes werden auch genutzt, um Datenlecks zu vermeiden, wenn Inhalte aus einer anderen Domain eingebettet werden.

Randnotiz für Entwickler*innen: Theoretisch könnte der H5P-Inhaltstyp direkt auf die Größenänderungsereignisse des Browserfensters hören, obwohl er sich in einem anderen Kontext befindet, aber aus zwei Gründen sollte er dies nicht tun:

  1. Es ist ein zusätzlicher benutzerdefinierter Listener, der nicht benötigt wird, und um den Code einfach zu halten, verwende einfach die vorhandene Schnittstelle, die der H5P.EventDispatcher bietet.
  2. Der H5P-Kern oder ein übergeordneter Inhaltstyp kann „resize events“ nicht nur dann an seine Kinder weiterleiten, wenn das Browserfenster seine Größe ändert, sondern kann sie auch aus anderen Gründen auslösen. Diese würden deinem Code entgehen, wenn du dich nur darauf verlassen würdest, dem window-Objekt einen Resize-Event-Listener zu spendieren.

Das neuerworbene Wissen nutzen

Es gibt noch mehr zu „resizing“, aber wir können bereits einige Phänomene mit dem Wissen erklären, das wir bisher gewonnen haben. Zum Beispiel:

Ich habe einige H5P-Inhalte in meine Seite aufgenommen, aber der untere Teil ist abgeschnitten!

Wo könnte das Problem liegen? Es könnte etwas mit dem Inhaltstyp zu tun haben. Ein Tipp: Der Inhalt könnte sich in der Höhe verändert haben, aber er hat den H5P-Kern nicht benachrichtigt, um seine Größe entsprechend anzupassen. Einfacher ausgedrückt: Es wurde vergessen, der übergeordneten Seite mitzuteilen, dass sie mehr Platz im Iframe benötigt. Infolgedessen konnte der untere Teil des Inhalts abgeschnitten werden. Diese Theorie passt zu dem, was wir gesehen haben.

Wir haben auch eine Möglichkeit, diese Theorie zu testen. Wir können die Größe des Browserfensters ändern, und wenn danach alles gut aussieht, ist es wahrscheinlich ein Problem damit, wie der Inhalt die Größenänderung handhabt.

Das gleiche Problem könnte auftreten, wenn am unteren Rand des Inhalts zusätzlicher Platz vorhanden ist, der verschwindet, wenn wir die Größe des Browserfensters ändern.

Ich habe einige H5P-Inhalte auf meiner Seite eingebettet, aber der untere Teil ist abgeschnitten!

Kannst du Unterschied zu dem vorherigen Phänomen erkennen? Das Ergebnis ist das gleiche, aber das Szenario ist ein wenig anders. Diese Aussage bedeutet, dass du einen HTML-Einbettungscode verwendet hast, um H5P-Inhalte in deine Seite zu integrieren. Zum Beispiel so:

Das ist der Demo-Inhalt für eine H5P-Multiple-Choice-Frage von h5p.org. Er läuft auf dem Server von h5p.org, aber wir sehen sie uns durch das Fenster im Umschlag an, das diese Seite ist.

Hier scheint alles reibungslos zu funktionieren. Allerdings kann es auch vorkommen, dass der iframe seine Höhe nicht anpasst, so dass Teile des Inhalts am unteren Rand abgeschnitten werden.

Schauen wir uns das mal genauer an: Die H5P-Inhalte funktionieren auf h5p.org einwandfrei, und auch Ihre Webseite läuft einwandfrei. Du kannst den Inhalt auf deiner Seite sehen. Was fehlt also? Richtig, das „Resizer-Skript“. Wir brauchen es, um die korrekte Größenänderung zu gewährleisten.

Der Einbettungscode, den du kopieren kannst, indem due auf den Button „Einbetten“ (oder „Embed“) unter dem H5P-Inhalt klickst, sieht folgendermaßen aus:

<iframe
  src="https://h5p.org/h5p/embed/712" width="1090" height="580"
  frameborder="0" allowfullscreen="allowfullscreen" allow="geolocation *;
  microphone *; camera *; midi *; encrypted-media *"
  title="Multiple Choice">
</iframe>

<script
  src="https://h5p.org/sites/all/modules/h5p/library/js/h5p-resizer.js"
  charset="UTF-8">
</script>

Aus Gründen der Übersichtlichkeit habe ich einige Zeilenumbrüche eingefügt, aber das ist für die Funktionalität nicht von Bedeutung.

Die wichtige Tatsache ist: Wenn es darum geht, H5P-Inhalte in seine HTML-Seite einzufügen, wirst du zwei wesentliche Dinge braucen: ein iframe-Tag und ein script`-Tag.

Das iframe-Tag erstellt ein Fenster für den H5P-Inhalt und lädt ihn von einer bestimmten URL. Außerdem übernimmt es einige zusätzliche Aufgaben, die für andere Aspekte relevant sind.

Das script-Tag weist deine Seite an, ein Stück JavaScript-Code von einer bestimmten URL einzubinden. Hast du bemerkt, dass die Skriptdatei „h5p-resizer.js“ heißt? Dies ist ein wichtiger Teil des H5P-Kerns, der die Kommunikation zwischen deiner Seite und dem H5P-Inhalt übernimmt. Ohne ihn weiß der H5P-Inhalt nicht, wenn das Browserfenster seine Größe ändert. Wenn der H5P-Inhalt seine Größe ändert, sendet der H5P-Kern innerhalb des iframes eine Nachricht, aber niemand hört zu, so dass der iframe seine Größe nicht ändern kann.

Aber Moment mal, wenn wir das script-Tag einfügen, sollte doch alles gut funktionieren, oder? Aber was ist, wenn du es hinzugefügt hast und es immer noch nicht funktioniert? In diesem Fall solltest du dir den HTML-Code deiner Seite noch einmal ansehen. Es besteht die Möglichkeit, dass der iframe-Tag vorhanden ist, aber das script-Tag fehlt. Warum ist das so?

Viele Plattformen filtern aus Sicherheitsgründen script-Tags vollständig heraus. Sie wollen verhindern, dass möglicherweise schädlicher Code in die Seite eingeschleust wird. Leider bedeutet dies, dass du in solchen Fällen keine H5P-Inhalte mit Größenanpassung einbetten kannst.

Wenn du Glück hast, lassen einige Plattformen script-Tags zu, die auf JavaScript-Dateien verweisen, die auf demselben Server gehostet werden – aber nur, wenn ein Administrator diese Dateien geprüft und genehmigt hat. Man muss nicht unbedingt das vorgeschlagene Skript h5p-resizer.js von https://h5p.org/sites/all/modules/h5p/library/js/h5p-resizer.js verwenden. Ein Administrator könnte es herunterladen, sich vergewissern, dass es sicher ist, und es dann auf demselben Server wie deine Plattform hosten. Ich könnte die Datei z. B. auf https://snordian.de/whateverNameILike.js hochladen und sie verwenden, um zu vermeiden, dass Code von Servern Dritter auf meiner Seite ausgeführt wird.

Alternativ dazu könnte der Administrator das Skript auf jeder Seite laden, unabhängig davon, ob sie H5P-Inhalte enthält oder nicht. Eine andere Möglichkeit ist, ein kleines Skript zu erstellen, das das Skript zur Größenanpassung nur dann lädt, wenn sich ein iframe mit H5P-Inhalt auf der Seite befindet.

Puh, das war schon eine ganze Menge!

Auf jeden Fall! Wir haben wir eine ganze Menge behandelt, aber es gibt noch mehr zu entdecken. Die Größenänderung von H5P-Inhalten ist in verschiedenen Szenarien von Bedeutung. Nehmen wir zum Beispiel H5P.Column. Das hat keine spezifischen Elemente, die dem H5P-Kern eine Größenänderung signalisieren müssen, und es kann vom Browser nahtlos in der Größe verändert werden. H5P.Column enthält jedoch Unterinhaltstypen, die möglicherweise das gesamte Prozedere der Größenänderung erfordern.

Dies bringt uns zu…

Dieser Inhalt verhält sich seltsam: Er skaliert nicht richtig, sieht verzerrt aus, ist falsch platziert, …

Wenn du es mit einem „Wrapper“-Inhaltstyp wie Column zu tun hast, spielt dieser eine entscheidende Rolle bei der Verwaltung von Größenänderungsereignissen für seine Unterinhalte. Er muss alle Größenänderungsereignisse, die er vom H5P-Kern erhält, an seine Unterinhalte weitergeben. Auf diese Weise können die Unterinhalte bei Bedarf ihre Berechnungen und Aktionen zur Größenänderung durchführen.

Umgekehrt muss der „Wrapper“-Inhaltstyp auch auf Größenänderungsereignisse achten, die von seinen Unterinhalten kommen. Er sollte diese Ereignisse an den H5P-Kern weiterleiten. Es muss jedoch darauf geachtet werden, dass dabei keine Endlosschleife entsteht.

Wenn du ein merkwürdiges Verhalten von Unterinhalten im Bezug auf die Größenänderung feststellst, könnte dies auf ein Problem mit einem Unterinhaltzurückzuführen sein, wenn dieser innerhalb eines „Wrapper“-Inhaltstyps und nicht als eigenständiger Inhalt verwendet wird. Oder der „Wrapper“-Inhaltstyp reicht möglicherweise Größenenderungsereignisse nicht korrekt durch.

Das erstgenannte Problem könnte erklären, warum du bestimmte H5P-Inhaltstypen nicht als Unterinhalte in anderen finden kannst. Sie könnten für sich allein gut funktionieren, stoßen aber unter Umständen auf Probleme, wenn sie als Unterinhalte verwendet werden, und sie erfordern dann mehr Überlegungen bei der Größenberechnung. Es ist jedoch zu beachten, dass ein fehlerhaftes Resizing nur ein möglicher Grund dafür ist, dass Inhalte innerhalb eines „Wrapper“-Inhaltstyps nicht wie erwartet funktionieren. Die anderen Gründe wären wohl Material für einen weiteren Artikel …

Immer noch nicht alles!?

Nein, die Welt der Größenanpassung ist noch viel größer. Es gibt ein recht häufiges Problem, das sogar eine eigene Seite in der H5P-Dokumentation auf h5p.org hat. Diese Seite ist allerdings nicht unbedingt selbsterklärend. Aber es sollte inzwischen nicht mehr allzu schwer zu erklären sein.

Ich habe H5P-Inhalte in dieses andere Akkordeon-Plugin, oder Tabs-Plugin, oder Lightbox-Plugin, … eingebunden.

Die Überschrift könnte weitergehen mit oder „in irgendeinem anderen Ding, das H5P-Inhalte in einen anderen Container mit unterschiedlicher Größe einfügt“, aber bleiben wir beim Akkordeon. Das Prinzip ist das gleiche.

Viele Plattformen bieten verschiedene Plugins an, die es dir ermöglichen, Inhalte in einem Akkordeon zu platzieren – und das bezieht sich nicht auf den Inhaltstyp H5P.Accordion. Normalerweise zeigen Akkordeons immer nur ein Feld auf einmal an, das sich erweitert, wenn du auf ein Panel klickst. Aber warum kann dies zu Problemen bei der Größenanpassung führen, wenn H5P-Inhalte in diesen Feldern platziert werden? Schauen wir uns das mal genauer an.

Stellen dir vor, du hast ein Akkordeon mit drei Bereichen, und du hast jedem Bereich H5P-Inhalte hinzugefügt. Wenn du die Seite lädst, ist der erste Bereich normalerweise ausgeklappt, so dass er eine sichtbare Höhe hat. Die beiden anderen Bereiche sind jedoch eingeklappt (oder „versteckt“) und haben eine Höhe von 0 Pixeln.

Jetzt kommt der H5P-Kern ins Spiel. Er versucht, die Höhe für jeden iframe des Inhalts auf der Grundlage des Containers, in dem er sich befindet, festzulegen. Wenn dieser Container eine Höhe von mehr als 0 Pixeln hat, funktioniert alles wie erwartet. H5P legt die Größe des iframe fest, und je nach Akkordeon-Panel kann die Höhe begrenzt oder angepasst werden, um den H5P-Inhalt anzupassen. In jedem Fall kannst du den Inhalt sehen.

Wenn der Container jedoch explizit oder implizit eine Höhe von 0 Pixeln hat, setzt H5P die Höhe des iframe ebenfalls auf 0 Pixel. Zu diesem Zeitpunkt spielt das keine Rolle, da die Panels 2 und 3 immer noch eingeklappt sind. Aber wenn du auf Panel 2 oder 3 klickst, passiert nichts; du kannst den H5P-Inhalt nicht sehen.

Was fehlt hier? Es ist unser alter Freund, das Resizer-Skript. Dieses Skript lauscht nur auf Größenänderungsereignisse des Browsers und weiß nichts über das Akkordeon-Panel, in dem es sich befindet. Es weiß also nicht, dass das Panel ausgeklappt wurde und nun mehr Platz bietet. Infolgedessen wird die Größe des iframe nicht geändert und es wird auch kein Größenänderungsereignis gesendet, um den H5P-Inhalt anzupassen.

Wie können wir diese Theorie überprüfen? Nun, wir können die Größe des Browserfensters nach dem Ausklappen eines Akkordeon-Panels ändern. Wenn der H5P-Inhalt sichtbar wird, bedeutet dies, dass ein vom Browser gesendetes Größenänderungsereignis das Problem behoben hat.

Es gibt mehrere Möglichkeiten, sich aus dieser Misere zu befreien, aber alle haben einen gewissen Preis.

  • Akkordeon-Plugin-Maintainer fügt JavaScript hinzu
    Die Entwickler*innen des Akkordeon-Plugins könnte eine einfache JavaScript-Codezeile einfügen, die ein Größenänderungs-Ereignis auslöst, wenn ein Panel ein- oder ausgeklappt wird. Etwas wie window.dispatchEvent(new Event('resize')); Dieses Ereignis würde den H5P-Kern informieren, dass die Größe des iframe s angepasst werden muss. Es stellt sich jedoch die Frage, warum der Maintainer/die Maintainerin ein anderes Plugin wie etwa H5P unterstützen sollte, wenn das Akkordeon selbst diese Funktion nicht benötigt.
  • H5P Group fügt maßgeschneiderten Code hinzu
    Die H5P Group könnte maßgeschneiderten Code hinzufügen, um andere Plugin-Container zu erkennen, in denen der H5P-iframe platziert sein könnte. Dieser Code würde es H5P ermöglichen, die Größe nach Bedarf anzupassen. Aber auch hier stellt sich die Frage: Warum sollte die H5P Group Code für verschiedene beliebige Plugins hinzufügen?
  • H5PGroup verwendet einen ResizeObserver
    Die H5P-Group könnte einen so genannten ResizeObserver im Resizer-Skript verwenden. Dieser „Observer“ würde prüfen, ob der übergeordnete Container (z. B. das Akkordeon-Panel) seine Größe geändert hat, und den H5P-Kern auffordern, die Größe des iframes entsprechend zu ändern. Es ist jedoch schwierig, automatisch festzustellen, ob der ResizeObserver notwendig ist. Und fügt man ihn bedingungslos hinzu, könnte es zu Ineffizienzen führen.
  • Erstellen eines Workarounds mit „gefälschten“ Größenänderungsereignissen
    Abhilfe könnte darin bestehen, in regelmäßigen Abständen „gefälschte“ Browser-Größenänderungsereignisse zu senden, um sicherzustellen, dass H5P-Inhalte angezeigt werden. Dies würde zwar funktionieren, könnte aber ressourcenintensiv sein und zu Leistungsproblemen führen, insbesondere auf weniger leistungsfähigen Geräten.
    Die Verarbeitung eines Größenänderungsereignisses kann kostspielig sein und sollte nicht leichtfertig ausgelöst werden. Bei einem einzelnen, eigenständigen Inhaltstyp wie einem Multiple-Choice-Quiz, bei dem ein Größenänderungsereignis keine Rolle spielt, ist das vielleicht nicht so wichtig. Aber du könntest auch Inhalte mit mehreren verschachtelten Unterinhalten haben, die alle Berechnungen und Aktionen zur Größenänderung durchführen. Das wird Rechenressourcen binden. Stellen dir nun vor, dass du dies auf einem Gerät mit geringerer Leistung wie einem Smartphone tust. Stell dir vor, dass das Intervall für die Größenänderung auf 100 ms reduziert wird. Das führt zu 10 Größenänderungsereignissen pro Sekunde, möglicherweise um eine sichtbare Verzögerung zu vermeiden … Das würde die Benutzeroberfläche irgendwann zäh machen und zu Flackern oder anderen Dingen führen, die du nicht willst …
  • Erstellen eines Workarounds mit ResizeObserver
    Eine Lösung könnte einen ResizeObserver auf H5P-iframes implementieren, der die Größenänderung nur bei Bedarf auslöst. Du kannst den Teil „wenn nötig“ viel besser definieren als die H5P Group, da du weißt, welches Plugin du verwendst. Diese Methode ermöglicht eine bessere Kontrolle darüber, wann die Größenanpassung erfolgt, zugeschnitten auf das verwendete Plugin.
  • Erstellen eines Workarounds für Panel-Interaktionen
    Ein weiterer Workaround könnte die Überwachung von Panel-Klicks beinhalten, die zu Größenänderungen führen, und dann den H5P-iframe zur Größenänderung veranlassen. Dieser Ansatz würde eine Anpassung an das spezifische Akkordeon-Plugin erfordern, das verwendet wird.

Wenn du H5P auf WordPress einsetz und auf die oben genannten Probleme stößt, gibt es ein Plugin namens SNORDIAN’s H5P Resize Pulse, mit dem du eine der drei möglichen Workarounds wählen kannst, ohne selbst Code schreiben zu müssen. Du musst das Plugin nur installieren und konfigurieren.

Noch mehr?

Ja, mir fallen noch mehr Probleme ein, aber diese sollten nicht auftreten, wenn man die regulären H5P-Integrationen wie die H5P-Plugins für Moodle, WordPress oder Drupal oder H5P.com verwendet. Entwickler von H5P-Integrationen sollten sich jedoch dieser potenziellen Fallstricke bewusst sein.

Die Höhe des iframes springt hin und her

Manchmal kann es zu Wettläufen kommen, wenn der H5P-Kern und eine eigene H5P-Integration beide versuchen, die Größe des H5P-iframes zu ändern. Dies kann zu einem inkonsistenten Größenänderungsverhalten führen, bei dem die Höhe des iframes kurzzeitig hin und her springt, manchmal nur um 1 Pixel. In diesem Fall solltest du unbedingt die H5P-Integration überprüfen. Es sollte nicht notwendig sein, die Höhe des iframes manuell anzupassen oder zu versuchen, den von H5P bereitgestellten Größenänderungsprozess zu überlisten.

Nichts ändert sich (mit noch einem iframe)

Ich habe auch schon eigene H5P-Integrationen gesehen, die versucht haben, einen zusätzlichen iframe innerhalb ihrer Seite zu verwenden und dann den H5P-iframe innerhalb dieses zwischengeschalteten iframe zu platzieren. Bei dieser Konfiguration muss der dazwischenliegende iframe sein eigenes Skript zur Größenänderung haben, das die Größenänderungsereignisse zwischen der Seite und dem H5P-iframe weiterleitet. Ohne dieses zwischengeschaltete Skript funktioniert die Größenänderung nicht korrekt.

Letzte Worte

Ich hoffe, ich habe kein anderes Problem mit der H5P-Größenanpassung übersehen, auf das du stoßen könntest … Wenn doch, lass es mich bitte wissen, und ich werde eine Ergänzung schreiben.