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]);