Kontakt
============================================================ */ (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); }); } })();