Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.
============================================================ */ (function () { 'use strict'; /* ---------- Konfiguration ---------- */ var EASE = 0.08; /* Easing-Stärke (kleiner = weicher/träger) */ var WHEEL_SPEED = 1.0; /* Mausrad-Empfindlichkeit */ var TOUCH_SPEED = 1.0; /* Touch/Swipe-Empfindlichkeit */ /* ---------- DOM ---------- */ var wrapper = document.querySelector('.slider-wrapper'); var track = document.querySelector('.slider-track'); if (!wrapper || !track) { console.warn('[Slider] .slider-wrapper oder .slider-track nicht gefunden.'); return; } var originalRows = Array.from(track.children); if (originalRows.length === 0) { console.warn('[Slider] Keine .slider-row Elemente gefunden.'); return; } /* ---------- Klonen ---------- */ /* Klon-Set nach den Originalen anhängen */ originalRows.forEach(function (row) { var clone = row.cloneNode(true); /* Lazy-Loading auf Klonen deaktivieren → keine fehlenden Bilder */ clone.querySelectorAll('img[loading="lazy"]').forEach(function (img) { img.setAttribute('loading', 'eager'); }); track.appendChild(clone); }); /* Klon-Set vor den Originalen einfügen — rückwärts iterieren, damit die Reihenfolge im DOM korrekt bleibt [row1, row2, row3, row4] (insertBefore + firstChild dreht sonst die Reihenfolge um) */ for (var i = originalRows.length - 1; i >= 0; i--) { var clone = originalRows[i].cloneNode(true); clone.querySelectorAll('img[loading="lazy"]').forEach(function (img) { img.setAttribute('loading', 'eager'); }); track.insertBefore(clone, track.firstChild); } /* Nach dem Klonen: track.children[0 .. n-1] = Klon-Set vor track.children[n .. 2n-1] = Originale track.children[2n .. 3n-1] = Klon-Set nach */ var n = originalRows.length; /* ---------- setHeight: DOM-Messung statt Formel ---------- */ /* * Wir messen die Distanz zwischen dem ersten Original und dem ersten * Klon-nach direkt im DOM. Da beide im selben transform-Container * liegen, kürzt sich ein eventuell laufender translateY heraus. * Das ergibt exakte Werte auch wenn Bilder unterschiedlich groß sind. */ function getSetHeight() { var rectA = track.children[n].getBoundingClientRect(); var rectB = track.children[n * 2].getBoundingClientRect(); return rectB.top - rectA.top; } /* ---------- Zustand ---------- */ var setHeight = 0; var currentY = 0; var targetY = 0; function init() { setHeight = getSetHeight(); if (setHeight <= 0) return; /* Noch nicht gerendert – abwarten */ currentY = -setHeight; targetY = -setHeight; /* translate3d statt translateY → GPU-Compositing, kein Layout-Thrash */ track.style.transform = 'translate3d(0,' + currentY + 'px,0)'; } /* ---------- Animations-Loop ---------- */ function animate() { /* Nahtloser Loop: target und current gemeinsam verschieben → Momentum und Easing bleiben erhalten, kein sichtbarer Sprung */ while (targetY <= -(2 * setHeight)) { targetY += setHeight; currentY += setHeight; } while (targetY >= 0) { targetY -= setHeight; currentY -= setHeight; } currentY += (targetY - currentY) * EASE; track.style.transform = 'translate3d(0,' + currentY + 'px,0)'; requestAnimationFrame(animate); } /* ---------- Events ---------- */ wrapper.addEventListener('wheel', function (e) { e.preventDefault(); targetY -= e.deltaY * WHEEL_SPEED; }, { passive: false }); var lastTouchY = 0; wrapper.addEventListener('touchstart', function (e) { lastTouchY = e.touches[0].clientY; }, { passive: true }); wrapper.addEventListener('touchmove', function (e) { var dy = e.touches[0].clientY - lastTouchY; lastTouchY = e.touches[0].clientY; targetY += dy * TOUCH_SPEED; e.preventDefault(); }, { passive: false }); /* ---------- Start ---------- */ /* Warten bis alle Bilder geladen sind, damit getSetHeight() korrekte Höhen misst */ function start() { init(); animate(); /* Sicherheitsnetz: nach 500 ms nochmal messen, falls Bilder nach window.load per Webflow-Lazy nachladen */ setTimeout(init, 500); } if (document.readyState === 'complete') { start(); } else { window.addEventListener('load', start); } /* ---------- Resize ---------- */ var resizeTimer; if (window.ResizeObserver) { new ResizeObserver(function () { clearTimeout(resizeTimer); resizeTimer = setTimeout(init, 150); }).observe(wrapper); } else { window.addEventListener('resize', function () { clearTimeout(resizeTimer); resizeTimer = setTimeout(init, 150); }); } })();