Signatur
Beschreibung
Das scrollend-Ereignis feuert einmal, sobald ein Scrollvorgang eines Elements beendet ist. Das gilt, wenn der Nutzer nicht mehr aktiv scrollt (Finger losgelassen, Mausrad ruht, Taste losgelassen) und alle nachlaufenden Bewegungen wie Trägheitsscrollen, scroll-snap-Einrasten oder eine per scrollTo({ behavior: "smooth" }) gestartete Animation fertig sind.
Bisher musste man das Ende des Scrollens mit einem entprellten scroll-Handler und setTimeout erraten. Das war ungenau und verzögert. scrollend ersetzt dieses Muster. Typische Anwendungen sind: die Scrollposition speichern, Inhalte nachladen, sobald die Liste ruht, in Karussells mit Scroll-Snap den aktiven Slide bestimmen oder aufwendige Berechnungen erst nach dem Scrollen ausführen.
Registrieren kann man den Handler mit element.addEventListener("scrollend", handler) oder über die Eigenschaft element.onscrollend = handler. Das Ereignis ist ein einfaches Event, steigt nicht auf (kein Bubbling) und lässt sich nicht abbrechen. Für das Scrollen des ganzen Dokuments hört man auf document oder window (dort steigt das Ereignis zum window auf).
Hat sich die Scrollposition gar nicht geändert, zum Beispiel weil scrollTo() die aktuelle Position als Ziel hatte oder der Nutzer am Rand weiterscrollt, wird kein scrollend ausgelöst.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignistyp, hier immer "scrollend". |
|
| $handler Pflicht | (event: Event) => void | EventListenerObject | Die Rückruffunktion. Sie erhält ein einfaches Event-Objekt ohne Positionsdaten, deshalb liest man die Position über event.target.scrollTop bzw. scrollLeft. |
|
| $options | boolean | AddEventListenerOptions | false | Optionale Einstellungen wie once, passive, signal oder capture. |
Rückgabewert
addEventListener gibt nichts zurück. Der Handler bekommt ein Event mit bubbles: false und cancelable: false.Beispiele
Scrollposition nach dem Scrollen speichern
const liste = document.querySelector('#artikel-liste');
// Gespeicherte Position wiederherstellen
liste.scrollTop = Number(sessionStorage.getItem('listePos') ?? 0);
liste.addEventListener('scrollend', (event) => {
const pos = event.target.scrollTop;
sessionStorage.setItem('listePos', String(pos));
console.log(`Position gespeichert: ${pos}px`);
});
Aktiven Slide im Scroll-Snap-Karussell bestimmen (on-Property)
const karussell = document.querySelector('.karussell');
const anzeige = document.querySelector('#slide-nr');
karussell.onscrollend = () => {
const breite = karussell.clientWidth;
const index = Math.round(karussell.scrollLeft / breite);
anzeige.textContent = `Slide ${index + 1}`;
console.log('Eingerastet auf Slide', index + 1);
};
// Handler wieder entfernen:
// karussell.onscrollend = null;
Auf Ende eines Smooth-Scrolls warten (Promise) und Listener entfernen
const scrollUndWarten = (el, top) => new Promise((resolve) => {
if (el.scrollTop === top) return resolve(); // kein scrollend zu erwarten
const fertig = () => {
el.removeEventListener('scrollend', fertig);
resolve();
};
el.addEventListener('scrollend', fertig);
el.scrollTo({ top, behavior: 'smooth' });
});
const main = document.querySelector('main');
await scrollUndWarten(main, 1200);
console.log('Animation beendet, Element fokussieren');
document.querySelector('#kapitel-3')?.focus();
Fallback mit Entprellung für ältere Browser
const onScrollEnde = (el, callback) => {
if ('onscrollend' in window) {
el.addEventListener('scrollend', callback);
return;
}
let timer;
el.addEventListener('scroll', (e) => {
clearTimeout(timer);
timer = setTimeout(() => callback(e), 150);
}, { passive: true });
};
onScrollEnde(document, () => console.log('Scrollen beendet'));
// Wichtig · Fallstricke
- Browserunterstützung: Chrome/Edge ab 114 und Firefox ab 109 unterstützen das Ereignis. Safari unterstützt es erst in sehr neuen Versionen (26). Deshalb die Unterstützung mit
'onscrollend' in windowprüfen und bei Bedarf auf einen entprelltenscroll-Handler zurückfallen. - Kein Bubbling: Auf einem Elternelement kommen
scrollend-Ereignisse von Kind-Scrollcontainern nicht an. Wer sie trotzdem zentral abfangen will, registriert den Listener in der Capture-Phase ({ capture: true }). - Keine Änderung, kein Ereignis: Bleibt die Scrollposition gleich, feuert nichts. Promise-basierte Wrapper sollten diesen Fall selbst abfangen, sonst warten sie ewig.
- Das Ereignis wartet, bis der Nutzer loslässt. Solange ein Finger auf dem Touchscreen liegt oder die Scrollleiste gezogen wird, kommt kein
scrollend, auch wenn die Position gerade ruht. - Für Aktualisierungen während des Scrollens (z. B. Fortschrittsbalken) ist weiterhin
scrollgedacht, für Sichtbarkeit von Elementen besserIntersectionObserver.