{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "scroll-snap-ereignisse",
 "name": "Scroll-Snap-Ereignisse",
 "name_en": "Scroll snap events: scrollsnapchange and scrollsnapchanging",
 "kurz": "Zimmer-Karussell, Bildergalerie und Nächte-Rad eines Seehotels melden über scrollsnapchanging schon während der Geste, wohin sie wollen, und über scrollsnapchange, wo sie liegen; ohne die Ereignisse rechnet scrollend nach.",
 "kategorie": "Galerien & Slider",
 "kategorie_slug": "galerien-slider",
 "kategorie_nr": 12,
 "bau_chat": "C6",
 "prioritaet": "F",
 "trendstatus": "aufsteigend",
 "belegstatus": "quellenbelegt",
 "website_belege": 0,
 "stimmung": [
  "ruhig",
  "editorial",
  "luxuriös"
 ],
 "stimmung_roh": [
  "ruhig",
  "editorial",
  "luxuriös"
 ],
 "technik": [
  "css",
  "vanilla-js",
  "scroll-snap",
  "aria-live"
 ],
 "technik_gruppen": [
  "css",
  "js",
  "andere"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "Ein natives Scroll-Snap-Band meldet selbst, wo es einrastet. scrollsnapchanging feuert schon während der Geste, sobald der Browser das neue Ziel vorhersieht, scrollsnapchange erst, wenn es liegt. Daraus werden ohne IntersectionObserver ein Zähler „03 / 06“, eine Bildunterschrift, die schon beim Wischen wechselt, ein Kapitelstatus oder ein Auswahlrad, dessen Wert erst beim Einrasten gilt. Browser ohne die Ereignisse rechnen das Ziel bei scrollend selbst aus.",
  "warum_es_wirkt": "Zähler und Bildunterschrift, die erst nach dem Loslassen springen, wirken träge; solche, die bei jedem Pixel flackern, wirken nervös. Die zwei Ereignisse trennen genau das: Vorschau während der Geste, Festlegung beim Einrasten. Der Code wird kurz, weil der Browser das Ziel kennt.",
  "wann_einsetzen": "Zimmer- und Galerie-Karussells mit Zähler und Bildtext (Hotel, Fotograf, Immobilien, Weingut), Bildergalerien mit Daumenleiste, Auswahlräder für Nächte, Personen oder Uhrzeit in einer Buchungsleiste.",
  "wann_nicht": "Nicht als einzige Steuerung: Pfeile, Tastatur und sichtbare Position gehören dazu (karussell-steuerung). Nicht für Seiten, die als ganze Folien einrasten (fullpage-snap-slides). Nicht für Werte, die man exakt eintippt; ein Auswahlrad ersetzt kein Zahlenfeld bei großen Bereichen.",
  "varianten": [
   "Zimmer-Karussell: Zähler und Bildunterschrift wechseln schon während der Geste, Status „wechselt“ und „eingerastet“, Pfeile, Tastatur",
   "Galerie mit Daumenleiste: ein Bild je Ansicht, die Daumenleiste folgt schon in der Geste, festgelegt beim Einrasten",
   "Auswahlrad: Nächte als senkrechtes Snap-Rad, Preis rechnet beim Wischen vor (≈) und gilt beim Einrasten"
  ],
  "umsetzung": "1. Band mit scroll-snap-type: x mandatory (Kapitel: y mandatory), Kinder mit scroll-snap-align: center bzw. start. 2. Erkennung: const kannSnap = 'onscrollsnapchange' in window. 3. Mit Unterstützung: band.addEventListener('scrollsnapchanging', e => vorschau(e.snapTargetInline)) setzt nur die leichte Vorschau (Zähler, Bildtext, Preis vorläufig); band.addEventListener('scrollsnapchange', e => festlegen(e.snapTargetInline)) setzt den gültigen Zustand (aria-current, Ansage, Wert). Bei senkrechten Bändern snapTargetBlock. 4. Rückfall: scrollend (Chrome 114, Firefox 109, Safari 26.2) ruft festlegen(naechstes()), naechstes() vergleicht die Mitte jedes Kindes mit der Mitte des Bandes. Für die Vorschau im Rückfall ein scroll-Handler mit requestAnimationFrame, der dasselbe rechnet. Ohne scrollend ein Timer 120 ms nach dem letzten scroll. 5. Pfeile und Tastatur rufen scrollIntoView({ inline: 'center', block: 'nearest' }) bzw. scrollBy; die Ereignisse kommen dann von selbst. 6. Zähler mit tabellarischen Ziffern, Wechsel per kurzem Versatz; Ansage nur bei scrollsnapchange, nie bei scrollsnapchanging.",
  "mobil": "Wischen ist hier die Hauptbedienung; Pfeile bleiben trotzdem als 44-px-Knöpfe. Das Auswahlrad nutzt die native Trägheit; der Wert gilt erst beim Einrasten.",
  "reduzierte_bewegung": "Pfeile springen ohne Gleiten (behavior: auto). Zähler und Bildtext wechseln ohne Versatz. Wischen selbst bleibt, das ist Bedienung.",
  "barrierefreiheit": "Band als Region mit Namen, Folien als Gruppe mit „3 von 6“. Pfeile sind echte Knöpfe, Pfeiltasten im fokussierten Band. Ansage per aria-live nur beim Einrasten. Das Auswahlrad ist role=\"spinbutton\"-artig mit Pfeiltasten und aria-valuenow, plus sichtbare Knöpfe Minus und Plus."
 },
 "messwerte": {
  "easing": "cubic-bezier(0.37, 0, 0.63, 1) für Bild und Text (Rezept boutique-hotel-gastgeber); UI cubic-bezier(0.16, 1, 0.3, 1)",
  "dauer_ms": "Bildtext-Wechsel 300, Zähler 220, Rückfall-Timer 120",
  "stagger_ms": "",
  "distanz": "Zähler 0,6 em Versatz",
  "sonstiges": "Ansage nur beim Einrasten",
  "herkunft": "eigene Festlegung",
  "quelle": "Rezept boutique-hotel-gastgeber"
 },
 "kurve": {
  "bezier": [
   0.37,
   0.0,
   0.63,
   1.0
  ],
  "css": "cubic-bezier(0.37, 0, 0.63, 1)",
  "name": "sine.inOut",
  "dauer_ms": 300
 },
 "gesehen_bei": [
  {
   "seite": "Chrome for Developers: Scroll Snap Events",
   "url": "https://developer.chrome.com/blog/scroll-snap-events",
   "auszeichnung": "",
   "beobachtung": "Abgerufen 05.11.2026: Seit Chrome 129. scrollsnapchange feuert, wenn die Geste mit neuem Ziel endet, kurz vor scrollend; scrollsnapchanging schon während der Geste, sobald das neue Ziel vorhergesagt wird, bei langsamem Wischen mehrfach. snapTargetInline bzw. snapTargetBlock enthalten das Element. Erkennung über 'onscrollsnapchange' in window.",
   "art": "artikel"
  },
  {
   "seite": "caniuse: Element API scrollsnapchange",
   "url": "https://caniuse.com/mdn-api_element_scrollsnapchange_event",
   "auszeichnung": "",
   "beobachtung": "Abgerufen 05.11.2026: Chrome und Edge ab 129, Samsung Internet ab 28; Firefox bis 162 und Safari bis 27.2 ohne Unterstützung. Rund 72 % weltweit.",
   "art": "artikel"
  },
  {
   "seite": "web.dev: Interop 2026",
   "url": "https://web.dev/blog/interop-2026",
   "auszeichnung": "",
   "beobachtung": "Abgerufen 05.11.2026: Scroll Snap ist Schwerpunkt von Interop 2026; ob die Ereignisse dazugehören, sagt der Beitrag nicht.",
   "art": "artikel"
  }
 ],
 "tutorials": [
  {
   "titel": "Chrome for Developers: Scroll Snap Events",
   "url": "https://developer.chrome.com/blog/scroll-snap-events"
  },
  {
   "titel": "MDN: SnapEvent",
   "url": "https://developer.mozilla.org/en-US/docs/Web/API/SnapEvent"
  },
  {
   "titel": "MDN: scrollend",
   "url": "https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollend_event"
  }
 ],
 "kombinierbar_mit": [
  "css-native-karussell",
  "karussell-steuerung",
  "buchungsleiste-datumsbereich",
  "scrollspy-kapitelnavigation",
  "tabellenziffern",
  "zahlen-odometer"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/galerien-slider/scroll-snap-ereignisse/",
  "meta": "https://cecodesign.de/lab/fundus/galerien-slider/scroll-snap-ereignisse/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/galerien-slider/scroll-snap-ereignisse/demo"
 },
 "herkunft": {
  "quelldateien": [
   "Recherche Runde 4, 04.11.2026"
  ],
  "pruefnotizen": [
   "Browserstand 05.11.2026 (caniuse): scrollsnapchange und scrollsnapchanging nur in Chromium (Chrome und Edge ab 129, Samsung 28). Firefox bis 162 und Safari bis 27.2 nicht. Rückfall über scrollend ist Pflicht; scrollend laut caniuse Chrome 114, Firefox 109, Safari 26.2.",
   "Abgrenzung: karussell-steuerung zeigt Steuerungen (Zähler per scroll-Ereignis), css-native-karussell kommt ohne JS aus. Dieses Muster ist die Ereignis-Schicht für Zustände während und nach der Geste.",
   "Kein Award-Beleg; Werte eigene Festlegung aus dem Rezept boutique-hotel-gastgeber.",
   "Demo 05.11.2026: Nach dem Wechsel von display: none auf sichtbar meldete Chromium (headless) einmal scrollsnapchange mit dem Ziel von scrollTop 0, obwohl das Rad schon auf dem gesetzten Wert stand. Das Rad gleicht deshalb beim Festlegen mit der Lage ab (Math.round(scrollTop / Zeilenhöhe))."
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Zimmer-Karussell, Bildergalerie und Nächte-Rad eines Seehotels melden über scrollsnapchanging schon während der Geste, wohin sie wollen, und über scrollsnapchange, wo sie liegen; ohne die Ereignisse rechnet scrollend nach.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "erkennung": "'onscrollsnapchange' in window (?rueckfall erzwingt den Rückfall)",
   "vorschau": "scrollsnapchanging → e.snapTargetInline bzw. snapTargetBlock: Zähler, Bildtext, Daumen, Preis ≈; keine Ansage",
   "fest": "scrollsnapchange → aria-current, Pfeile an/aus, aria-live-Ansage, Preis gilt",
   "rueckfall": "scroll + requestAnimationFrame → Vorschau (nächstes Kind zur Mitte bzw. zum Anfang); scrollend → fest; ohne scrollend Timer 120 ms",
   "gleiches_ziel": "Vorschau auf das schon gültige Ziel setzt den Zustand still zurück (kein Schweben, keine Ansage)",
   "zaehler": "Newsreader 300, 1lh-Maske; alte Zahl 160 ms cubic-bezier(0.7, 0, 0.84, 0) nach oben, neue 220 ms cubic-bezier(0.16, 1, 0.3, 1) von 0,6 em",
   "bildtext": "alt 140 ms aus, neu 300 ms cubic-bezier(0.37, 0, 0.63, 1) mit 80 ms Verzug, 6 px",
   "status": "Punkt 8 px gefüllt = eingerastet, hohl = wechselt",
   "zimmer": "scroll-snap-type x mandatory, align start, Karten clamp(240px, 30vw, 380px) 4:5; aktives Bild scale 1.06 → 1 in 900 ms",
   "galerie": "x mandatory, align center, scroll-snap-stop always, 16:9 max. 62svh; Daumen 76 × 52",
   "rad": "y mandatory, 56 px je Zeile, 168 px hoch mit Maskenverlauf; role=spinbutton, Pfeiltasten, Bild auf/ab ±3, Pos1/Ende; Abgleich mit Math.round(scrollTop / 56)",
   "preis": "148 € je Nacht, Intl.NumberFormat de-DE EUR, Abreise per Intl.DateTimeFormat",
   "schrift": "Newsreader opsz 72 300–400 für Titel und Zahlen, Mona Sans wdth 100 Text, wdth 118 Versal-Labels",
   "farben": "#F3EEE7 Sand, #FEF2E3 Creme, #3E3A37 Text, #6A6C67 Meta, #6E5A47 Holz"
  },
  "ausloeser": "ziehen",
  "touch": "Wischen ist die Hauptbedienung; Pfeile bleiben als 48-px-Knöpfe. Rad mit nativer Trägheit, Minus und Plus daneben. Karten auf dem Telefon 78 % breit, damit die nächste anschneidet.",
  "reduziert": "Pfeile und Rad springen ohne Gleiten, Zähler und Bildtext wechseln ohne Versatz, kein Zurückskalieren der Bilder. Wischen bleibt (Bedienung).",
  "korrekturen": {
   "varianten": [
    "Zimmer-Karussell: Zähler und Bildunterschrift wechseln schon während der Geste, Status „wechselt“ und „eingerastet“, Pfeile, Tastatur",
    "Galerie mit Daumenleiste: ein Bild je Ansicht, die Daumenleiste folgt schon in der Geste, festgelegt beim Einrasten",
    "Auswahlrad: Nächte als senkrechtes Snap-Rad, Preis rechnet beim Wischen vor (≈) und gilt beim Einrasten"
   ]
  },
  "geprueft": "05.11.2026",
  "notiz": "Welt: Rezept boutique-hotel-gastgeber, erfundenes Haus Kranichsee in Neustrelitz am Zierker See. Newsreader und Mona Sans, Sand und Holz, Bilder hotel-*, fenster-licht, Zeichnungen aus bild-zoom-in-maske und slideshow-innere-gegenparallaxe. Browserstand 05.11.2026 (caniuse): Ereignisse nur Chromium ab 129, Firefox bis 162 und Safari bis 27.2 nicht; scrollend Chrome 114, Firefox 109, Safari 26.2. Vorführung: Band rückt alle 2,2 s eine Folie weiter, Rad springt 2, 5, 7, 3 Nächte. Abgrenzung: karussell-steuerung (Steuerungen), css-native-karussell (ohne JS). Selbsturteil 4.",
  "varianten": [
   {
    "id": "zimmer",
    "name": "Zimmer-Karussell",
    "wann": "Hotel, Ferienwohnung, Immobilien: Karten mit Bildtext und Preis, Zähler und Status neben dem Band.",
    "werte": {
     "snap": "x mandatory, start",
     "vorschau": "Zähler, Bildtext, Status „wechselt“"
    }
   },
   {
    "id": "galerie",
    "name": "Galerie mit Daumenleiste",
    "wann": "Fotograf, Exposé, Weingut: ein großes Bild je Ansicht, Daumen zum Springen.",
    "werte": {
     "snap": "x mandatory, center, snap-stop always",
     "vorschau": "Daumen halb markiert, Zähler, Bildtext"
    }
   },
   {
    "id": "rad",
    "name": "Auswahlrad",
    "wann": "Buchungsleisten für Nächte, Personen oder Uhrzeit mit kleinem Wertebereich.",
    "werte": {
     "snap": "y mandatory, 56 px",
     "vorschau": "Preis mit ≈ und gedämpfter Farbe",
     "fest": "aria-valuenow, Ansage mit Abreise und Preis"
    }
   }
  ]
 }
}
