Ping pong balls

/Links-in-Single-Page-Apps?sie=scrollen#doch

Ein kurzer Blick auf Hash-Links, auf fehlendes Scrollen in Single-Page-Apps und darauf, wie wir Scrivito-Anwendungen von diesem Makel befreit haben.

Die Historie

In der schönen neuen Welt der JavaScript-basierten Single Page Apps (SPAs) läuft das meiste nicht mehr wie früher auf dem Server ab, sondern im Client, also im Browser auf dem Gerät des Benutzers.

Leider unterbleibt viel zu häufig etwas, das bisher vom Browser übernommen wurde: Seiten scrollen nicht mehr zu der Stelle, die durch den Hash-Teil in der URL spezifiziert ist.

Wenn wir uns exemplarisch das abschließende „#syntax-references” in w3.org/TR/html52/infrastructure.html#syntax-references ansehen und diesem Link folgen, scrollt der Browser automatisch zum Abschnitt „References”, wie vom hintersten Teil der URL vorgegeben. Folgt man einem Hash-Link innerhalb der Seite oder zu einer anderen Seite derselben Website, wird ebenfalls dorthin gescrollt.

Woran liegt’s?

Bei modernen SPAs gibt es keine „anderen Seiten” mehr, sondern nur noch eine einzige, die „Single Page”. SPAs registrieren sich als Klick-Handler für Links und ändern dann den Status der App entsprechend. Die Browser-Logik, die das referenzierte Element in den sichtbaren Ausschnitt scrollt, kommt gar nicht erst zum Zuge.

Um die ganze Angelegenheit noch etwas spannender zu machen, laden dynamische Websites ihre Inhalte asynchron nach. Dabei werden die Bestandteile der Seite nicht auf einen Schlag, sondern nach und nach sichtbar. Nicht einmal die neusten Browser können den URL-Hash, die Lage des Seitenfragments und die entsprechende Scroll-Position synchron halten. Das trifft auch auf Scrivito-Anwendungen als Exemplare moderner dynamischer SPAs zu.

Lösungsansätze

Dieses Ärgernis beschäftigt uns und einige unserer Kunden schon seit geraumer Zeit, in deren Verlauf wir natürlich auf diverse Lösungsversuche gestoßen sind. Sie reichen von benutzerdefinierten Handlern, die einen Teil der Schwierigkeiten gut in den Griff bekommen, hin zu Bibliotheken von Drittanbietern, die sich eines anderen Teils annehmen.

Letztendlich konnte keiner dieser Ansätze sämtliche typischen Anwendungsfälle abdecken:

  • Wenn man die Website mit einem Hash in der URL besucht, sollte die betreffende Seite beim Laden zum referenzierten Element scrollen.
  • Wenn man auf einen Hash-Link auf derselben Seite klickt, sollte sie zu dem entsprechenden Element scrollen.
  • Folgt man einem Hash-Link zu einer anderen URL auf derselben Website, sollte ebenfalls erwartungsgemäß gewechselt und gescrollt werden.

Die Bibliotheken, die wir uns in der Hoffnung angesehen haben, dass sie die oben genannten Anforderungen erfüllen, machen ihre jeweilige Sache zwar gut, haben aber leider alle dieselbe Schwäche: sie decken längst nicht die ganzen Anwendungsfälle ab, die wir für uns ermittelt haben.

  • react-hash-link hat einen guten Ansatz, mit dynamisch hinzugefügten Inhalten umzugehen: es erkennt DOM-Mutationen und behandelt zahlreiche Fälle, jedoch nicht alle unserigen. Ein Blick in den Code hat uns schnell erkennen lassen, dass die zugrunde liegende Logik relativ simpel ist und wir lieber unsere eigene Version entwickeln sollten, anstatt zu versuchen, diesen Code umzubauen.

  • react-scroll ist sehr vielseitig, stützt sich aber auf React-Komponenten, wodurch sich die Komplexität der Anwendung erhöht. Diese Bibliothek wird in der Scrivito Example App verwendet, funktioniert allerdings nicht bei HTML-Inhalten, die im CMS gespeichert sind, wie etwa unsere interne API-Dokumentation.

Wir haben uns gern von diesen Lösungen inspirieren lassen, um dann unsere eigene zu entwickeln:

Scroll-to-fragment!

Unser Helper, natürlich zu finden auf npmjs.org, versieht Single-Page-Anwendungen mit dem klassischen Scroll-Verhalten. Er aktualisiert die Scroll-Position beim Laden, und bei Klicks und Änderungen im Browser-Verlauf erkennt er Aktualisierungen. Um das Fragment (den Hash) mit asynchron nachgeladenem Inhalt (etwa in einer ReactJS-basierten Anwendung) aktuell zu halten, passt er auch die Scroll-Position bei DOM-Änderungen an.

Die Bibliothek kann leicht zur App hinzugefügt und initialisiert werden. Alles Weitere finden Sie im Readme zum Package.

Unsere Bibliothek wird kontinuierlich aktualisiert, damit SPAs bezüglich ihres Scroll-Verhaltens stets so funktionieren, wie man es von klassischen Anwendungen her kennt. Wir haben versucht, sie ohne jeden Bezug auf Frameworks zu bauen. Da wir uns allerdings in erster Linie auf React und Scrivito konzentrieren, rechnen wir damit, dass Benutzer anderer Frameworks und Entwicklungsumgebungen nicht abgedeckte Anwendungsfälle finden. Darüber wüssten wir dann gerne mehr.

Wenn Sie etwas vermissen oder einen neuen Sonderfall gefunden haben – von denen es nach unserer Einschätzung viele geben dürfte –, freuen wir uns, wenn Sie von sich hören lassen. Noch schicker fänden wir einen Pull-Request von Ihnen!

Abschließend bleibt nur noch hinzuzufügen, dass diese Bibliothek hoffentlich eines Tages von modernen Standards und besserem Standardverhalten der Browser abgelöst wird. Bis dahin: Viel Spaß damit!

Scrivito CMS: der Content-Hub für Ihre Websites und Apps

Scrivito CMS ist unsere komplette Unternehmenslösung für Digital-Experience-Plattformen, Websites und Webanwendungen der nächsten Generation. Als Software as a Service benötigt Scrivito keine IT-Wartung. Das Content-Management-System ist äußerst flexibel und erfüllt höchste Sicherheitsstandards.