/** * Ultra-Smooth Scroll Header - Butter Performance * Uses advanced techniques for maximum smoothness */ document.addEventListener("DOMContentLoaded", function() { const topBanner = document.querySelector('.top-banner'); const slideMenu = document.querySelector('.slide-menu'); if (!topBanner) return; // Configuration for ultra-smooth performance const scrollThreshold = 50; const rafDelay = 8; // 120fps for ultra-smooth const transitionDuration = 400; // Slightly longer for smoother feel // State tracking with performance optimization let isScrolled = false; let lastScrollY = 0; let scrollDirection = 'down'; let rafId = null; let lastUpdateTime = 0; let scrollVelocity = 0; let lastScrollTime = 0; // Calculate scroll velocity for smoother transitions function calculateVelocity(currentScrollY, currentTime) { if (lastScrollTime === 0) { lastScrollTime = currentTime; return 0; } const timeDelta = currentTime - lastScrollTime; const scrollDelta = Math.abs(currentScrollY - lastScrollY); const velocity = scrollDelta / timeDelta; lastScrollTime = currentTime; return velocity; } // Ultra-smooth header state update with velocity-based easing function updateHeaderState(scrolled, velocity = 0) { if (scrolled === isScrolled) return; // Add velocity-based class for different transition speeds if (velocity > 5) { topBanner.classList.add('fast-scroll'); } else { topBanner.classList.remove('fast-scroll'); } // Use requestAnimationFrame for smooth DOM updates requestAnimationFrame(() => { if (scrolled) { topBanner.classList.add('scrolled'); if (slideMenu) { slideMenu.style.transition = 'top 0.3s cubic-bezier(0.4, 0, 0.2, 1)'; slideMenu.style.top = '80px'; } } else { topBanner.classList.remove('scrolled'); if (slideMenu) { slideMenu.style.transition = 'top 0.3s cubic-bezier(0.4, 0, 0.2, 1)'; slideMenu.style.top = '110px'; } } }); isScrolled = scrolled; } // Advanced scroll handler with velocity detection function handleScroll(currentTime) { // Ultra-high frequency throttling if (currentTime - lastUpdateTime < rafDelay) { rafId = requestAnimationFrame(handleScroll); return; } const currentScrollY = window.pageYOffset || document.documentElement.scrollTop; const velocity = calculateVelocity(currentScrollY, currentTime); // Detect scroll direction with hysteresis for stability const scrollDelta = currentScrollY - lastScrollY; if (Math.abs(scrollDelta) > 1) { scrollDirection = scrollDelta > 0 ? 'down' : 'up'; } // Apply hysteresis to prevent flickering let shouldScroll; if (scrollDirection === 'down') { shouldScroll = currentScrollY > scrollThreshold + 10; } else { shouldScroll = currentScrollY > scrollThreshold - 10; } updateHeaderState(shouldScroll, velocity); lastScrollY = currentScrollY; lastUpdateTime = currentTime; rafId = null; } // Optimized scroll listener with passive event function onScroll() { if (!rafId) { rafId = requestAnimationFrame(handleScroll); } } // Add scroll listener with maximum performance window.addEventListener('scroll', onScroll, { passive: true, capture: false }); // Handle resize with debouncing let resizeTimeout; function onResize() { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(() => { lastScrollY = window.pageYOffset || document.documentElement.scrollTop; updateHeaderState(lastScrollY > scrollThreshold); }, 100); } window.addEventListener('resize', onResize, { passive: true }); // Handle visibility change to pause/resume animations function onVisibilityChange() { if (document.hidden) { if (rafId) { cancelAnimationFrame(rafId); rafId = null; } } else { lastScrollY = window.pageYOffset || document.documentElement.scrollTop; updateHeaderState(lastScrollY > scrollThreshold); } } document.addEventListener('visibilitychange', onVisibilityChange); // Initialize with smooth transition requestAnimationFrame(() => { updateHeaderState(window.pageYOffset > scrollThreshold); }); // Add smooth scroll behavior to internal links document.querySelectorAll('a[href^="#"]').forEach(link => { link.addEventListener('click', function(e) { const targetId = this.getAttribute('href'); if (targetId === '#') return; const targetElement = document.querySelector(targetId); if (targetElement) { e.preventDefault(); // Smooth scroll with header offset const headerHeight = topBanner.offsetHeight; const targetPosition = targetElement.offsetTop - headerHeight - 20; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); } }); }); });