Wie man auf Mobilgeräten ungewolltes Website-Scrolling verhindert
Hallo Alle!
Bevor ich mit dem Thema dieses Posts anfange, muss ich ein paar Sachen erwähnen:
- Dieser Post ist ein Test-Post. Ich habe ihn geschrieben, um ein paar Sachen mit dieser Website auszuprobieren, nicht weil das Thema wirklich interessant ist.
- Dieser Post trifft nur auf die aktuelle Version dieser Website zu (siehe Veröffentlichungsdatum oben). Wenn du ihn liest, kann er schon komplett hinfällig sein.
Da das nun klar ist, los geht's!
Das Problem
Wenn du diese Website sowohl auf sowohl einem Mobil-, als auch einem Desktop-Gerät mal verwendet hast, dann wird dir aufgefallen sein, dass sie sich an die Größe deines Geräts anpasst. Das nennt man Responsive Design, und auch wenn es wichtig ist, ist es im heutigen Web nicht wirklich beeindruckend.
Ein Teil dieser Seite, das massiv davon beeinflusst wird, ist die Navigation. Wenn du einen großen Bildschirm hast, dann werden die einzelnen Navigationsziele direkt in der Kopfzeile angezeigt. Wenn du andererseits einen kleinen Bildschirm verwendest, dann sind sie hinter einem Hamburger-Menü versteckt. Das gleiche gilt auch für die Seitenleiste auf großen Bildschirmen, die am Handy über den Pfeil-Knopf geöffnet werden kann.
Wenn eines dieser beiden Menüs geöffnet ist, dann bedeckt es den gesamten Bildschirm. Wie du es erwarten würdest, kannst du dann nicht mit dem Inhalt dahinter interagieren. Vermutlich denkst du, dass sich der Browser automatisch darum kümmert.
Leider ist dem so nicht. Als Website-Autor muss man daran denken, dieses Verhalten zu implementieren. In diesem Post erkläre ich nun, wie ich das gemacht habe.
Wie die Menüs funktionieren
Bevor ich das jedoch machen kann, muss ich erklären wie die Menüs funktionieren.
Während JavaScript in (so gut wie) allen Browsern verfügbar ist, gibt es Leute, die es deaktivieren. Obwohl ich mit dieser Entscheidung dieser Leute nicht übereinstimme, möchte ich trotzdem, dass sie meine Seite verwenden können. Daher habe ich nach einem Weg gesucht, Menüs ohne JavaScript umzusetzen und habe ihn auf Stack Overflow gefunden.
Vereinfacht gesagt haben wir eine Checkbox, ein Label und ein <div>
mit dem Menüinhalt. Wir machen
die Checkbox und das Menü unsichtbar. Wenn die Checkbox abgehackt ist (der Benutzer hat auf das
Label getippt), machen wir den Inhalt wieder sichtbar.
Ein kleines Code-Beispiel:
1 2 Zeigen/Verbergen-Knopf
3 Inhalt
1
Versuch 1
Mit diesem Vorwissen über die Funktionsweise der Menüs können wir uns nun daran machen, das eigentliche Problem zu lösen.
Im Prinzip müssen wir nur überprüfen ob eine der Checkboxes abgehackt ist, und falls dem so sein
sollte das Scrollen für den <html>
-Tag sperren.
Der folgende Code repliziert die Funktionsweise meiner ersten Implementation. Ich habe ihn aber etwas aufgeräumt, damit ich später die Unterschiede gut zeigen kann.
1
Auf den ersten Blick scheint dieser Code zu funktionieren. Es gibt jedoch einen Haken.
Die Kopfzeile dieser Website bleibt immer am oberen Bildschirmrand. Die einzige Ausnahme dabei bilden vertikal kleine Geräte (wie z.B. Smartphones im Breitbildmodus), wo sie am oberen Ende der Seite bleibt. Das verursacht nun ein Problem.
Wenn der Benutzer nun auf seinem Handy ein Menü öffnet und es dann auf die Seite dreht, dann hat er plötzlich keine Möglichkeit mehr das Menü zu schließen. Hier ist ein Bild davon, wie es auf meinem Google Pixel 5 ausschaut:
Versuch 2
Wir können das obige Problem leicht lösen, indem wir die Kopfzeile am oberen Bildschirmrand fixieren, wenn ein Menü geöffnet ist. Wir können dafür die gleiche Methode verwenden wie bei allen anderen Geräten, nur dass wir sie jetzt in JavaScript statt CSS umsetzen müssen.
Auf meiner Seite benutze ich
position: sticky;
was bedeutet, dass ich auch top: 0;
setzen muss.
Im folgenden Snippet habe ich die Unterschiede im Vergleich zu vorher hervorgehoben.
1
Perfekt! Nun können die Benutzer das Menü immer schließen.
Jedoch gibt es immer noch ein Problem. Wenn jemand die Website in einem kleinen Browser-Fenster am PC öffnet, dann ein Menü öffnet und anschließend das Fenster so weit vergrößert, dass er das Desktop-Layout sieht, dann kann er weder das Menü schließen, noch scrollen. Das müssen wir beheben!
Versuch 3
Jetzt kommen wir zum kompliziertesten Teil. Wir müssen überprüfen, ob der Benutzer die Mobil- oder
Desktop-Variante sieht. Dafür gibt es verschiedene Techniken, man könnte etwat window.innerHeight
überprüfen.
Allerdings will ich nicht in mehreren Dateien Umbruchpunkte festlegen, daher werden wir ein bereits
existierendes Element verwenden. Dieses heißt #aside-toggle-closer
und wird im Desktop-Modus zu
display: none;
gesetzt.
Um die tatsächlichen Werte des Elements zu erhalten, müssen wir es zuerst an
window.getComputedStyle()
übergeben. element.style
enthält nur die Regeln für das jeweilige Element.
Nun können wir überprüfen ob es sich um ein Mobilgerät handelt, bevor wir das Scrollen sperren:
1
updateScrollLock()
aufrufen
Jetzt müssen wir nur noch die Funktion aufrufen, die wir gerade geschrieben haben. Wir müssen sie in drei Szenarien ausführen:
- beim Öffnen der Seite,
- beim Ändern der Fenstergröße und
- wenn eines der Menüs geöffnet oder geschlossen wird.
Wir können eine Funktion dafür schreiben:
1
Nun müssen wir nur noch diese Funktion beim Laden der Seite ausführen:
1 if document.readyState != "loading"
Die Hoffnung für weniger JavaScript
Obwohl diese Scroll-Sperre leicht umzusetzen ist, wie du gesehen hast, mag ich sie nicht.
Wenngleich ich nicht denke, dass der Einsatz von JavaScript perse ein Problem ist, so ist dies doch
das einzige Feature dieser Website, dass ich nicht ohne es umsetzen konnte, was mich wirklich nervt.
Das bedeutet aber auch, dass ich script-src: 'self'
in meiner
Content Security Policy haben muss.
Also habe ich nach einer CSS-Alternative gesucht, und auch eine gefunden:
:has()
. Dadurch sollte es möglich sein,
CSS wie dieses hier zu schreiben:
1
Vielleicht fragst du dich jetzt, warum ich diesen Post geschrieben habe, wenn es doch eine
CSS-Lösung gibt. Tja, wenn du die verlinkte Seite bis zum Ende liest, dann wirst du sehen, dass
derzeit kein Browser :has()
unterstützt. Als ich das herausgefunden habe, wirkte es wirklich wie
ein schlechter Scherz.
Also kann ich nichts machen außer warten und hoffen, dass ich dieses eine Script eines Tages von meiner Website entfernen kann.
Da das nun gesagt ist, wünsche ich dir einen schönen Tag!