Signatur
Beschreibung
Das Ereignis scrollsnapchange gehört zu den Scroll-Snap-Events. Es wird an einem Scroll-Container mit scroll-snap-type ausgelöst, sobald ein Scroll-Vorgang beendet ist und dabei ein neues Snap-Ziel feststeht. Es kommt kurz vor dem Ereignis scrollend. Hat sich das Snap-Ziel nicht geändert, etwa weil der Nutzer nur ein kleines Stück gescrollt hat und der Container zum selben Element zurückspringt, wird kein Ereignis ausgelöst.
Das Ereignisobjekt ist ein SnapEvent mit den Eigenschaften snapTargetBlock und snapTargetInline. Sie zeigen auf das Element, an dem in Block- bzw. Inline-Richtung eingerastet wurde. Rastet der Container in einer Richtung nicht ein, ist der Wert null. Ist das Snap-Ziel ein Pseudo-Element, wird das zugehörige Eltern-Element geliefert.
Typische Einsatzfälle sind Karussells, Slider und Vollbild-Sektionen. Dort lässt sich damit die aktive Folie markieren, eine Seitenanzeige („Punkte“) aktualisieren, Inhalte nachladen oder Analyse-Daten senden. Man muss dafür nicht bei jedem scroll-Ereignis Positionen berechnen oder einen IntersectionObserver einsetzen. Soll schon während des Scrollens reagiert werden, eignet sich das Schwester-Ereignis scrollsnapchanging.
Man registriert das Ereignis mit addEventListener("scrollsnapchange", …) oder über die Eigenschaft onscrollsnapchange. Es steigt nicht auf (bubbles: false) und lässt sich nicht abbrechen. Wird auf document gescrollt, geht das Ereignis an das Document.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "scrollsnapchange". |
|
| $handler Pflicht | (event: SnapEvent) => void | Callback, der ein SnapEvent mit snapTargetBlock und snapTargetInline erhält. |
|
| $options | boolean | AddEventListenerOptions | false | Optionen wie once, passive oder signal zum späteren Entfernen. |
Rückgabewert
addEventListener hat keinen Rückgabewert. Der Handler erhält ein SnapEvent.Beispiele
Aktive Folie eines Karussells markieren
// CSS: .carousel { overflow-x: auto; scroll-snap-type: x mandatory; }
// .slide { scroll-snap-align: center; }
const carousel = document.querySelector('.carousel');
carousel.addEventListener('scrollsnapchange', (event) => {
const target = event.snapTargetInline;
if (!target) return;
carousel.querySelector('.slide.active')?.classList.remove('active');
target.classList.add('active');
console.log('Neue Folie:', target.dataset.index);
});
Seitenanzeige über die on-Property aktualisieren
const slider = document.querySelector('#slider');
const dots = [...document.querySelectorAll('.dot')];
const slides = [...slider.children];
slider.onscrollsnapchange = ({ snapTargetInline }) => {
const index = slides.indexOf(snapTargetInline);
dots.forEach((dot, i) => dot.toggleAttribute('aria-current', i === index));
};
// Später wieder entfernen:
// slider.onscrollsnapchange = null;
Listener per AbortController entfernen und Fallback
const sections = document.querySelector('.sections'); // scroll-snap-type: y mandatory
const controller = new AbortController();
const onSnap = (event) => {
const section = event.snapTargetBlock;
console.log('Sektion erreicht:', section?.id);
if (section?.id === 'ende') controller.abort(); // Listener entfernen
};
if ('onscrollsnapchange' in window) {
sections.addEventListener('scrollsnapchange', onSnap, { signal: controller.signal });
} else {
// Fallback: scrollend + Positionsberechnung
sections.addEventListener('scrollend', () => {
const index = Math.round(sections.scrollTop / sections.clientHeight);
console.log('Sektion (Fallback):', sections.children[index]?.id);
}, { signal: controller.signal });
}
// Wichtig · Fallstricke
- Browser-Unterstützung: Bisher nur in Chromium-Browsern (Chrome/Edge ab 129). Firefox und Safari unterstützen das Ereignis noch nicht. Prüfe die Unterstützung mit
'onscrollsnapchange' in windowund nutze sonstscrollendoder einenIntersectionObserver. - Das Ereignis wird nur ausgelöst, wenn der Container tatsächlich Scroll-Snapping nutzt (
scroll-snap-typeam Container,scroll-snap-alignan den Kindern). - Es wird nicht ausgelöst, wenn das Snap-Ziel gleich bleibt. Außerdem kommt es erst am Ende des Scroll-Vorgangs. Für Rückmeldungen schon während der Geste gibt es
scrollsnapchanging. snapTargetBlockbzw.snapTargetInlineistnull, wenn in dieser Richtung nicht eingerastet wird. Prüfe den Wert deshalb immer vor der Verwendung.- Das Ereignis steigt nicht auf. Eine Ereignisdelegation über Eltern-Elemente funktioniert daher nicht, der Listener muss direkt am Scroll-Container hängen.
- Auch Snapping durch Code (z. B.
scrollTo()oderscrollIntoView()) und durch Änderungen am Layout kann das Ereignis auslösen.