Start · Sprachen · JavaScript · Referenz · VisualViewport: scrollend

VisualViewport: scrollend

Ereignis

Wird ausgelöst, sobald eine Scroll-Bewegung des visuellen Viewports (z. B. Verschieben beim Pinch-Zoom) vollständig abgeschlossen ist.

seit JavaScript Chrome/Edge 114+, Firefox 109+; Safari: nicht unte Kategorie: webapi

Signatur

window.visualViewport.addEventListener("scrollend", handler)

Beschreibung

Das scrollend-Ereignis des VisualViewport-Interfaces wird ausgelöst, wenn eine Scroll-Bewegung des visuellen Viewports endet. Der visuelle Viewport ist der tatsächlich sichtbare Bildschirmausschnitt. Auf Mobilgeräten kann er sich gegenüber dem Layout-Viewport verschieben, etwa wenn der Nutzer hineingezoomt hat und den Ausschnitt mit dem Finger bewegt oder wenn die Bildschirmtastatur erscheint.

Das Ereignis feuert erst, wenn alle Scroll-Updates fertig sind: Die Touch- bzw. Zeigerinteraktion ist beendet und auch eine ausklingende Bewegung (Momentum) oder ein weiches Scrollen (Smooth Scrolling) ist vorbei. Damit brauchst du für „Scrollen ist vorbei“ keine eigene Entprellung mit setTimeout auf das scroll-Ereignis mehr.

Typische Anwendungen: Fest positionierte Elemente wie Werkzeugleisten oder Hinweis-Banner nach dem Verschieben des Ausschnitts neu an offsetLeft/offsetTop ausrichten, Positionsdaten sparsam protokollieren oder aufwendige Neuberechnungen erst nach Ende der Bewegung ausführen.

Den Handler registrierst du mit visualViewport.addEventListener("scrollend", handler) oder über die Eigenschaft visualViewport.onscrollend. Das Ereignis ist ein einfaches Event, das nicht abgebrochen werden kann und nicht nach oben weitergereicht wird (kein Bubbling).

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignistyp, hier "scrollend".
$handler Pflicht (event: Event) => void | EventListenerObject Funktion, die nach Ende der Scroll-Bewegung aufgerufen wird. event.target ist das VisualViewport-Objekt.
$options boolean | AddEventListenerOptions false Optionen wie once, passive oder signal (AbortSignal zum Entfernen des Handlers).

Beispiele

Endposition nach dem Verschieben protokollieren

const vv = window.visualViewport;

if (vv) {
  vv.addEventListener('scrollend', () => {
    console.log(`Scroll beendet: offset=(${vv.offsetLeft.toFixed(0)}, ${vv.offsetTop.toFixed(0)}), scale=${vv.scale}`);
  });
}
Scroll beendet: offset=(120, 340), scale=2

Werkzeugleiste nach dem Scrollen am sichtbaren Ausschnitt ausrichten

const toolbar = document.querySelector('#toolbar');
const vv = window.visualViewport;

const placeToolbar = () => {
  // Leiste unten im sichtbaren Bereich halten, Zoom ausgleichen
  const x = vv.offsetLeft;
  const y = vv.offsetTop + vv.height - toolbar.offsetHeight / vv.scale;
  toolbar.style.transform = `translate(${x}px, ${y}px) scale(${1 / vv.scale})`;
  toolbar.hidden = false;
};

// Während der Bewegung ausblenden, danach neu platzieren
vv.addEventListener('scroll', () => { toolbar.hidden = true; }, { passive: true });
vv.addEventListener('scrollend', placeToolbar);
vv.addEventListener('resize', placeToolbar);

on-Property verwenden und Handler wieder entfernen

const vv = window.visualViewport;

// Variante 1: on-Property
vv.onscrollend = () => console.log('scrollend über onscrollend');
// Entfernen:
vv.onscrollend = null;

// Variante 2: addEventListener mit AbortController
const controller = new AbortController();
vv.addEventListener('scrollend', () => console.log('scrollend'), { signal: controller.signal });

// Später, z. B. beim Verlassen einer Ansicht:
controller.abort();

Feature-Erkennung mit Ersatzlösung per Entprellung

const vv = window.visualViewport;
const onEnd = () => console.log('Viewport-Scroll beendet');

if (vv && 'onscrollend' in vv) {
  vv.addEventListener('scrollend', onEnd);
} else if (vv) {
  // Ersatz für Browser ohne scrollend (z. B. Safari)
  let timer;
  vv.addEventListener('scroll', () => {
    clearTimeout(timer);
    timer = setTimeout(onEnd, 150);
  }, { passive: true });
}
Viewport-Scroll beendet

// Wichtig · Fallstricke

  • Browser-Unterstützung: Chromium-Browser ab Version 114 und Firefox ab 109 unterstützen das Ereignis. Safari unterstützt scrollend derzeit nicht. Prüfe deshalb vorher mit 'onscrollend' in visualViewport und sieh eine Ersatzlösung per Entprellung vor.
  • Visueller und Layout-Viewport: visualViewport meldet nur Verschiebungen des sichtbaren Ausschnitts, etwa beim Zoomen oder durch die Bildschirmtastatur. Normales Scrollen des Dokuments ohne Zoom löst meist das scrollend-Ereignis von window/document aus. Für die Seite selbst registrierst du es also dort.
  • Kein Ereignis ohne Bewegung: Ändert sich die Position nicht, etwa weil der Nutzer schon am Rand ist oder ein scrollTo() zur aktuellen Position führt, feuert scrollend nicht.
  • Zoom-Änderungen: Reine Größen- oder Zoom-Änderungen lösen resize aus, nicht scrollend. Registriere für eine zuverlässige Positionierung beide Ereignisse.
  • visualViewport kann in manchen Umgebungen (ältere Browser, bestimmte WebViews) null bzw. undefined sein. Greife deshalb nur nach einer Prüfung darauf zu.
  • Das Ereignis wird nicht nach oben weitergereicht und lässt sich nicht abbrechen. preventDefault() bewirkt nichts.