Signatur
Beschreibung
Das Ereignis scrollsnapchanging gehört zu den Scroll-Snap-Ereignissen aus CSS Scroll Snap Module Level 2. Am Document wird es ausgelöst, wenn das Dokument selbst der Scroll-Container ist, also wenn für das Wurzelelement (<html>) scroll-snap-type gesetzt ist und die Seite als Ganzes scrollt. Das Ereignis tritt auf, sobald der Browser feststellt, dass ein anderes Snap-Ziel als bisher ausgewählt würde, wenn die laufende Scroll-Geste (Wischen, Mausrad, Ziehen der Scrollleiste, Tastatur) jetzt endete.
Damit eignet sich scrollsnapchanging für sofortiges visuelles Feedback noch während des Scrollens: z. B. um den Abschnitt hervorzuheben, auf den gerade eingerastet würde, einen Indikator im Karussell zu verschieben oder eine Navigation vorab zu aktualisieren. Das Gegenstück scrollsnapchange wird erst ausgelöst, wenn das Scrollen beendet und ein neues Ziel tatsächlich eingerastet ist – dort gehören „teure“ oder endgültige Aktionen hin (Daten laden, Analytics, URL aktualisieren).
Der Handler erhält ein SnapEvent. Dessen Eigenschaften snapTargetBlock und snapTargetInline enthalten das vorläufige Snap-Ziel in Block- bzw. Inline-Richtung oder null, wenn es in dieser Achse kein Ziel gibt. Registriert wird das Ereignis per document.addEventListener("scrollsnapchanging", …) oder über die Eigenschaft document.onscrollsnapchanging. Das Ereignis ist nicht abbrechbar.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "scrollsnapchanging". |
|
| $handler Pflicht | (event: SnapEvent) => void | Callback, der ein SnapEvent mit snapTargetBlock und snapTargetInline (jeweils Element | null) erhält. |
|
| $options | boolean | AddEventListenerOptions | false | Übliche Listener-Optionen wie passive, once oder signal. |
Rückgabewert
addEventListener gibt nichts zurück. Der Handler bekommt ein SnapEvent-Objekt übergeben.Beispiele
Anstehenden Abschnitt beim Scrollen hervorheben
// CSS: html { scroll-snap-type: y mandatory; }
// section { scroll-snap-align: start; height: 100vh; }
let pending = null;
document.addEventListener("scrollsnapchanging", (event) => {
pending?.classList.remove("is-pending");
pending = event.snapTargetBlock;
pending?.classList.add("is-pending");
console.log("Würde einrasten auf:", pending?.id);
});
Über die on-Property mit Seiten-Indikator
const dots = document.querySelectorAll(".pager-dot");
const sections = [...document.querySelectorAll("section")];
document.onscrollsnapchanging = (event) => {
const index = sections.indexOf(event.snapTargetBlock);
dots.forEach((dot, i) => dot.classList.toggle("active", i === index));
};
// Handler wieder entfernen:
// document.onscrollsnapchanging = null;
Feature-Erkennung, Kombination mit scrollsnapchange und Entfernen
const onChanging = (e) => {
document.body.dataset.preview = e.snapTargetBlock?.id ?? "";
};
const onChange = (e) => {
// Endgültige Aktion erst nach dem Einrasten
history.replaceState(null, "", `#${e.snapTargetBlock?.id ?? ""}`);
};
if ("onscrollsnapchanging" in document) {
document.addEventListener("scrollsnapchanging", onChanging);
document.addEventListener("scrollsnapchange", onChange);
} else {
console.log("Scroll-Snap-Events nicht unterstützt – Fallback per IntersectionObserver");
}
// Später aufräumen:
const cleanup = () => {
document.removeEventListener("scrollsnapchanging", onChanging);
document.removeEventListener("scrollsnapchange", onChange);
};
// Wichtig · Fallstricke
- Browser-Unterstützung: Bisher nur in Chromium-Browsern (Chrome/Edge ab 129). Firefox und Safari unterstützen das Ereignis derzeit nicht – immer per
"onscrollsnapchanging" in documentprüfen und ggf. aufIntersectionObserveroderscrollendausweichen. - Am
Documentkommt das Ereignis nur an, wenn das Dokument selbst der Snap-Container ist (scroll-snap-typeaufhtml). Für innere Container den Listener direkt am jeweiligen Element registrieren. - Das Ereignis kann während einer einzigen Geste mehrfach feuern, wenn der Nutzer hin- und herscrollt. Keine aufwendigen Operationen (Netzwerkaufrufe, Layout-lastige DOM-Änderungen) im Handler – dafür ist
scrollsnapchangegedacht. - Das vorläufige Ziel wird nicht zwingend das endgültige: Endet die Geste anders, feuert ggf. erneut
scrollsnapchangingmit dem ursprünglichen Ziel. snapTargetBlock/snapTargetInlinekönnennullsein – immer optional verketten (?.).