Start · Sprachen · JavaScript · Referenz · Element: scrollsnapchanging

Element: scrollsnapchanging

Ereignis

Wird auf dem Scroll-Container ausgelöst, sobald der Browser während einer Scroll-Geste ein neues Scroll-Snap-Ziel als bevorstehend erkennt.

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

Signatur

element.addEventListener("scrollsnapchanging", handler)

Beschreibung

Das Ereignis scrollsnapchanging wird auf einem Scroll-Container mit scroll-snap-type ausgelöst, wenn der Browser feststellt, dass ein neues Snap-Ziel aussteht. Das heißt: Würde die aktuelle Scroll-Geste jetzt enden, würde der Container auf ein anderes Element einrasten als bisher. Das Ereignis feuert also schon während des Scrollens bzw. Ziehens, oft mehrfach, und nicht erst am Ende.

Genau das unterscheidet es von scrollsnapchange. Dieses Ereignis feuert erst, wenn der Scroll-Vorgang abgeschlossen ist und ein neues Snap-Ziel tatsächlich übernommen wurde. scrollsnapchanging eignet sich daher für sofortiges visuelles Feedback. Beispiele sind ein vorläufig hervorgehobenes Karussell-Element, eine Vorschau der aktiven Seite in einer Paginierung oder ein Vorladen von Inhalten.

Der Handler erhält ein SnapEvent. Dessen Eigenschaften snapTargetBlock und snapTargetInline verweisen auf das ausstehende Snap-Ziel in der jeweiligen Achse. Gibt es in einer Achse kein Ziel, ist der Wert null. Das Ereignis lässt sich nicht abbrechen. Es blubbert (bubbles) nur, wenn es auf dem Document ausgelöst wird, auf Elementen dagegen nicht.

Du kannst den Handler per addEventListener("scrollsnapchanging", …) oder über die Eigenschaft onscrollsnapchanging registrieren. Scrollt die Seite selbst (Wurzel-Scroller), wird das Ereignis auf dem document bzw. über window ausgelöst.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname "scrollsnapchanging".
$handler Pflicht (event: SnapEvent) => void Callback, der ein SnapEvent mit snapTargetBlock und snapTargetInline erhält (jeweils Element | null).
$options boolean | AddEventListenerOptions false Übliche Listener-Optionen wie passive, once oder signal.

Beispiele

Ausstehendes Karussell-Element vorläufig hervorheben

// CSS: .carousel { overflow-x: auto; scroll-snap-type: x mandatory; }
//      .carousel > .slide { scroll-snap-align: center; }
const carousel = document.querySelector('.carousel');

carousel.addEventListener('scrollsnapchanging', (event) => {
  // Vorherige Markierung entfernen
  carousel.querySelector('.pending')?.classList.remove('pending');
  // Neues ausstehendes Ziel markieren
  const target = event.snapTargetInline;
  if (target) {
    target.classList.add('pending');
    console.log('Ausstehend:', target.dataset.index);
  }
});
Ausstehend: 2 Ausstehend: 3

Zusammenspiel mit scrollsnapchange (vorläufig vs. endgültig)

const list = document.querySelector('#pages');
const indicator = document.querySelector('#indicator');

// Sofortiges Feedback während der Geste
list.addEventListener('scrollsnapchanging', ({ snapTargetBlock }) => {
  if (snapTargetBlock) indicator.textContent = `→ Seite ${snapTargetBlock.dataset.page}`;
});

// Endgültiger Zustand nach Ende des Scrollens
list.addEventListener('scrollsnapchange', ({ snapTargetBlock }) => {
  if (snapTargetBlock) {
    indicator.textContent = `Seite ${snapTargetBlock.dataset.page}`;
    history.replaceState(null, '', `#page-${snapTargetBlock.dataset.page}`);
  }
});

Registrierung über onscrollsnapchanging mit Feature-Erkennung

const gallery = document.querySelector('.gallery');

if ('onscrollsnapchanging' in window) {
  gallery.onscrollsnapchanging = (event) => {
    console.log('Block:', event.snapTargetBlock?.id ?? null,
                'Inline:', event.snapTargetInline?.id ?? null);
  };
} else {
  console.log('scrollsnapchanging wird nicht unterstützt – Fallback per IntersectionObserver');
}

// Handler wieder entfernen
// gallery.onscrollsnapchanging = null;
Block: null Inline: img-4

// Wichtig · Fallstricke

  • Kompatibilität: Bisher nur in Chromium-Browsern verfügbar (Chrome/Edge 129+). Firefox und Safari unterstützen das Ereignis nicht. Prüfe die Unterstützung mit 'onscrollsnapchanging' in window und sieh einen Fallback vor, etwa mit IntersectionObserver oder scrollend.
  • Das Ereignis feuert nur, wenn der Container tatsächlich Scroll-Snapping nutzt. Dafür braucht der Container scroll-snap-type und die Kindelemente brauchen scroll-snap-align.
  • Während einer Geste kann das Ereignis mehrfach auslösen, z. B. wenn der Nutzer hin und her zieht. Das zuletzt gemeldete Ziel muss nicht das endgültige sein. Dauerhafte Aktionen wie Analytics, URL-Updates oder Datenabrufe gehören daher in scrollsnapchange.
  • Halte den Handler schlank und vermeide Layout-auslösende Zugriffe wie getBoundingClientRect in schneller Folge. Sonst kann das Scrollen ruckeln.
  • snapTargetBlock bzw. snapTargetInline können null sein, wenn in der jeweiligen Achse kein Snapping stattfindet. Prüfe den Wert immer vor dem Zugriff.
  • Beim Scrollen des gesamten Dokuments wird das Ereignis am document ausgelöst und nicht an document.documentElement.