From f298a9877c5b96a03b3e5b47aa0bce8e9a8e76ff Mon Sep 17 00:00:00 2001 From: Jason Guo <33064781+Xaroz@users.noreply.github.com> Date: Mon, 21 Oct 2024 12:44:07 -0400 Subject: [PATCH] fix: header scroll looping and firefox slow animation (#126) ## Scroll loop fix Fixed an issue where on some specific threshold it would cause the header to loop the scaling animation because of the height changes. Move timeoutId so the variable is not re-created everytime and added a missing logic that would prevent proper debouncing Caveat: If the scroll is extremely fast it might cause the header to be stuck on a certain threshold until a new scroll happens ## Firefox animation fix Fixed an issue with `Firefox` choppy and slow animation, basically some browsers struggle with animation because of the way they render a page, so the "trick" is to make the browser go into hardware acceleration mode by adding a slight `rotation` and this way the animations will run smoother --- src/components/nav/Header.tsx | 4 +++- src/utils/browser.ts | 3 --- src/utils/useScrollListener.ts | 23 ++++++++++------------- 3 files changed, 13 insertions(+), 17 deletions(-) delete mode 100644 src/utils/browser.ts diff --git a/src/components/nav/Header.tsx b/src/components/nav/Header.tsx index c9454732..5fea2781 100644 --- a/src/components/nav/Header.tsx +++ b/src/components/nav/Header.tsx @@ -31,9 +31,11 @@ export function Header({ pathName }: { pathName: string }) { >
+ {/* Add a minimal rotation here to trick the browser to go into hardware acceleration mode + this will make the animation a little smoother, specially for Firefox*/}
diff --git a/src/utils/browser.ts b/src/utils/browser.ts deleted file mode 100644 index c0a393fa..00000000 --- a/src/utils/browser.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function isFirefox() { - return typeof navigator !== 'undefined' && navigator.userAgent.toLowerCase().includes('firefox'); -} diff --git a/src/utils/useScrollListener.ts b/src/utils/useScrollListener.ts index a23981a1..ba73add0 100644 --- a/src/utils/useScrollListener.ts +++ b/src/utils/useScrollListener.ts @@ -1,19 +1,16 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; -import { isFirefox } from './browser'; - -export function useScrollThresholdListener(threshold: number, debounce = 500) { +export function useScrollThresholdListener(threshold: number, debounce = 300) { const [isAboveThreshold, setIsAbove] = useState(false); const [isDebouncing, setIsDebouncing] = useState(false); - useEffect(() => { - let timeoutId: NodeJS.Timeout | null; + const timeoutId = useRef(null); + useEffect(() => { const listener = () => { - // TODO find a way to make this animation smooth in Firefox - if (isFirefox()) return; - const handleScroll = () => { + if (isDebouncing) return; + if (window.scrollY > threshold && !isAboveThreshold) { setIsAbove(true); setIsDebouncing(true); @@ -24,10 +21,10 @@ export function useScrollThresholdListener(threshold: number, debounce = 500) { }; if (isDebouncing) { - if (!timeoutId) { - setTimeout(() => { + if (!timeoutId.current) { + timeoutId.current = setTimeout(() => { setIsDebouncing(false); - timeoutId = null; + timeoutId.current = null; handleScroll(); }, debounce); } @@ -39,7 +36,7 @@ export function useScrollThresholdListener(threshold: number, debounce = 500) { window.addEventListener('scroll', listener, { passive: true }); return () => { window.removeEventListener('scroll', listener); - if (timeoutId) clearTimeout(timeoutId); + if (timeoutId.current) clearTimeout(timeoutId.current); }; }, [threshold, debounce, isAboveThreshold, isDebouncing]);