Files
Websites/Profice WebSite/scripts/scroll-header.js
2026-02-06 09:30:59 +01:00

171 lines
5.7 KiB
JavaScript

/**
* 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'
});
}
});
});
});