Behalte die Kontrolle über das Scrollen – mit der Option „Zum Aktualisieren ziehen“ und „Überlauf“ kannst du die Effekte anpassen

Eric Bidelman
Majid Valipour

Kurzfassung

Mit der CSS-Eigenschaft overscroll-behavior können Entwickler das standardmäßige Scrollverhalten des Browsers überschreiben, wenn der Nutzer den oberen oder unteren Rand des Inhalts erreicht. Zu den Anwendungsfällen gehören die Deaktivierung der Funktion „Zum Aktualisieren ziehen“ auf Mobilgeräten, das Entfernen von Overscroll-Effekt- und Gummibandeffekten und das Verhindern des Scrollens von Seiteninhalten, wenn sie sich unter einem modalen/Overlay befinden.

Hintergrund

Scrollgrenzen und Scroll-Verkettung

Scrollverkettung in Chrome Android.

Scrollen ist eine der grundlegendsten Methoden zur Interaktion mit einer Seite. Bestimmte UX-Muster können jedoch aufgrund der ungewöhnlichen Standardverhalten des Browsers schwierig zu handhaben sein. Nehmen wir als Beispiel eine App-Leiste mit einer großen Anzahl von Elementen, durch die der Nutzer möglicherweise scrollen muss. Wenn sie den unteren Rand erreichen, stoppt der Überlaufcontainer das Scrollen, da keine Inhalte mehr verarbeitet werden müssen. Mit anderen Worten, der Nutzer erreicht eine „Scrollgrenze“. Aber achten Sie darauf, was passiert, wenn der Nutzer weiterscrollt. Der Inhalt hinter der Leiste scrollt nach oben. Das Scrollen wird vom übergeordneten Container übernommen – im Beispiel von der Hauptseite.

Es stellt sich heraus, dass dieses Verhalten als Scrollverkettung bezeichnet wird. Dies ist das Standardverhalten des Browsers beim Scrollen von Inhalten. Oft ist die Standardeinstellung ziemlich schön, aber manchmal ist sie unerwünscht oder unerwartet. Bestimmte Apps möchten möglicherweise eine andere Nutzererfahrung bieten, wenn der Nutzer eine Scrollgrenze erreicht.

Der Effekt „Zum Aktualisieren ziehen“

„Zum Aktualisieren ziehen“ ist eine intuitive Geste, die bei mobilen Apps wie Facebook und Twitter beliebt ist. Wenn Sie einen Social-Media-Feed aufrufen und loslassen, schaffen Sie neuen Platz für neuere Beiträge. Diese UX ist sogar so beliebt, dass mobile Browser wie Chrome für Android diesen Effekt zeigen. Wenn Sie oben auf der Seite nach unten wischen, wird die gesamte Seite aktualisiert:

Benutzerdefinierte Funktion „Zum Aktualisieren ziehen“ von Twitter,
wenn ein Feed in der PWA aktualisiert wird.
Mit der nativen Aktion zum Aktualisieren in Chrome Android
wird die gesamte Seite aktualisiert.

In Situationen wie der PWA von Twitter kann es sinnvoll sein, die native Aktion zum Aktualisieren durch Ziehen zu deaktivieren. Woran liegt das? In dieser Anwendung möchten Sie wahrscheinlich nicht, dass der Nutzer versehentlich die Seite aktualisiert. Es besteht auch die Möglichkeit, dass eine Animation doppelt aktualisiert wird. Unter Umständen ist es aber auch sinnvoller, die Aktion des Browsers anzupassen und ihn so besser auf das Branding der Website abzustimmen. Leider war diese Art der Anpassung nur schwer umzusetzen. Entwickler schreiben am Ende unnötigen JavaScript-Code, fügen nicht passive Touch-Listener hinzu, die das Scrollen blockieren, oder befestigen die gesamte Seite in einer 100VW/VH-<div>, damit sie nicht überläuft. Diese Behelfslösungen haben gut dokumentierte negative Auswirkungen auf die Scrollleistung.

Das können wir besser!

Jetzt neu: overscroll-behavior

Das Attribut overscroll-behavior ist eine neue CSS-Funktion, mit der sich steuern lässt, was passiert, wenn Sie in einem Container (einschließlich der Seite selbst) übermäßig scrollen. Sie können damit die Scroll-Verkettung abbrechen, die Aktion „Zum Aktualisieren durch Ziehen“ deaktivieren/anpassen, die Gummibandeffekte unter iOS deaktivieren (wenn Safari overscroll-behavior implementiert) und vieles mehr. Das Beste daran ist, dass sich die Verwendung von overscroll-behavior nicht nachteilig auf die Seitenleistung auswirkt, wie die in der Einführung erwähnten Hacks.

Das Attribut verwendet drei mögliche Werte:

  1. auto – Standardeinstellung. Scrollvorgänge, die vom Element ausgehen, können an Ancestor-Elemente weitergegeben werden.
  2. contains: verhindert die Verkettung von Scrollvorgängen. Scrollvorgänge werden nicht an Ancestors weitergegeben, aber lokale Effekte innerhalb des Knotens werden angezeigt. Zum Beispiel der Overscroll-Glow-Effekt unter Android oder der Gummibanding-Effekt unter iOS, bei dem der Nutzer benachrichtigt wird, wenn er eine Scrollgrenze erreicht. Hinweis: Wenn Sie overscroll-behavior: contain für das Element html verwenden, werden Overscroll-Navigationsaktionen verhindert.
  3. none: Wie contain, verhindert aber auch Overscroll-Effekte im Knoten selbst (z.B. Android-Overscroll-Glowing oder iOS-Rubberbanding).

Sehen wir uns einige Beispiele zur Verwendung von overscroll-behavior an.

Verhindern, dass Scrollvorgänge an einem Element mit fester Position vorbeigehen

Das Chatbox-Szenario

Inhalte unter dem Chatfenster scrollen auch :(

Denken Sie an ein fest positioniertes Chatfeld, das sich unten auf der Seite befindet. Das Ziel besteht darin, dass das Chatfeld eine eigenständige Komponente ist und getrennt vom Inhalt dahinter gescrollt wird. Aufgrund der Scroll-Verkettung beginnt das Dokument jedoch zu scrollen, sobald der Nutzer die letzte Nachricht im Chatprotokoll öffnet.

Für diese Anwendung ist es besser, wenn Scrolls, die aus dem Chatfenster stammen, innerhalb des Chats bleiben. Dazu fügen wir dem Element, das die Chatnachrichten enthält, overscroll-behavior: contain hinzu:

#chat .msgs {
  overflow: auto;
  overscroll-behavior: contain;
  height: 300px;
}

Im Wesentlichen schaffen wir eine logische Trennung zwischen dem Scrollkontext des Chatfelds und der Hauptseite. Das Endergebnis ist, dass die Hauptseite angezeigt bleibt, wenn der Nutzer den oberen/unteren Bereich des Chatprotokolls erreicht. Scrolls, die im Chatfenster beginnen, werden nicht weitergegeben.

Das Seiten-Overlay-Szenario

Eine weitere Variante des „underscroll“-Szenarios ist, wenn Inhalte hinter einem Overlay mit fester Position scrollen. Ein totes Werbegeschenk overscroll-behavior ist in Ordnung! Der Browser möchte hilfreich sein, aber dadurch sieht die Website fehlerhaft aus.

Beispiel – modales Fenster mit und ohne overscroll-behavior: contain:

Vorher: Der Seiteninhalt wird unter das Overlay gescrollt.
Nachher: Der Seiteninhalt scrollt nicht unter das Overlay.

Zum Aktualisieren ziehen deaktivieren

Das Deaktivieren der Aktion "Zum Aktualisieren ziehen" erfolgt über eine einzelne CSS-Zeile. Verhindern Sie einfach eine Scrollverkettung für das gesamte Element, das den Darstellungsbereich definiert. In den meisten Fällen ist dies <html> oder <body>:

body {
  /* Disables pull-to-refresh but allows overscroll glow effects. */
  overscroll-behavior-y: contain;
}

Mit dieser einfachen Ergänzung korrigieren wir die doppelten Animationen zum Aktualisieren durch Ziehen in der Chatbox-Demo und können stattdessen einen benutzerdefinierten Effekt implementieren, der eine ansprechendere Ladeanimation enthält. Außerdem wird der gesamte Posteingang unkenntlich gemacht, während er aktualisiert wird:

Vorher
Nachher

Hier ist ein Snippet des vollständigen Codes:

<style>
  body.refreshing #inbox {
    filter: blur(1px);
    touch-action: none; /* prevent scrolling */
  }
  body.refreshing .refresher {
    transform: translate3d(0,150%,0) scale(1);
    z-index: 1;
  }
  .refresher {
    --refresh-width: 55px;
    pointer-events: none;
    width: var(--refresh-width);
    height: var(--refresh-width);
    border-radius: 50%;
    position: absolute;
    transition: all 300ms cubic-bezier(0,0,0.2,1);
    will-change: transform, opacity;
    ...
  }
</style>

<div class="refresher">
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
</div>

<section id="inbox"><!-- msgs --></section>

<script>
  let _startY;
  const inbox = document.querySelector('#inbox');

  inbox.addEventListener('touchstart', e => {
    _startY = e.touches[0].pageY;
  }, {passive: true});

  inbox.addEventListener('touchmove', e => {
    const y = e.touches[0].pageY;
    // Activate custom pull-to-refresh effects when at the top of the container
    // and user is scrolling up.
    if (document.scrollingElement.scrollTop === 0 && y > _startY &&
        !document.body.classList.contains('refreshing')) {
      // refresh inbox.
    }
  }, {passive: true});
</script>

Deaktivieren der Overscroll-Glow- und Gumbanding-Effekte

Verwenden Sie overscroll-behavior-y: none, um den Bounce-Effekt beim Erreichen einer Scroll-Grenze zu deaktivieren:

body {
  /* Disables pull-to-refresh and overscroll glow effect.
     Still keeps swipe navigations. */
  overscroll-behavior-y: none;
}
Vorher: Wenn Sie die Scroll-Grenze erreichen, wird ein Leuchten angezeigt.
Nachher: Leuchten deaktiviert.

Vollständige Demo

Die vollständige Chatbox-Demo verwendet overscroll-behavior, um eine benutzerdefinierte Animation zum Aktualisieren durch Ziehen zu erstellen und das Umschreiben von Scrolls durch das Chatbox-Widget zu deaktivieren. Dies bietet eine optimale Nutzererfahrung, die ohne CSS-overscroll-behavior nur schwer zu erreichen gewesen wäre.

Demo ansehen | Quelle