Start · Sprachen · JavaScript · Referenz · Element: scrollsnapchange

Element: scrollsnapchange

Ereignis

Wird am Ende eines Scroll-Vorgangs am Scroll-Container ausgelöst, wenn ein neues Scroll-Snap-Ziel ausgewählt wurde, unmittelbar bevor das <code>scrollend</code>-Ereignis folgt.

seit JavaScript Chrome/Edge 129+ (experimentell, nicht Baseline) Kategorie: webapi

Signatur

element.addEventListener("scrollsnapchange", handler)

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

Typ
void
Beschreibung
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);
});
Neue Folie: 2

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 });
}
Sektion erreicht: intro Sektion erreicht: ende

// 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 window und nutze sonst scrollend oder einen IntersectionObserver.
  • Das Ereignis wird nur ausgelöst, wenn der Container tatsächlich Scroll-Snapping nutzt (scroll-snap-type am Container, scroll-snap-align an 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.
  • snapTargetBlock bzw. snapTargetInline ist null, 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() oder scrollIntoView()) und durch Änderungen am Layout kann das Ereignis auslösen.