Skip to content

Commit

Permalink
fix: header scroll looping and firefox slow animation (#126)
Browse files Browse the repository at this point in the history
## 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
  • Loading branch information
Xaroz authored Oct 21, 2024
1 parent 90a3d93 commit f298a98
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 17 deletions.
4 changes: 3 additions & 1 deletion src/components/nav/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ export function Header({ pathName }: { pathName: string }) {
>
<div className="flex items-center justify-between">
<Link href="/" className="flex items-center">
{/* 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*/}
<div
className={`flex items-center ${
animateHeader && 'scale-90'
animateHeader && 'rotate-[0.01deg] scale-90'
} transition-all duration-500 ease-in-out`}
>
<Image src={Logo} alt="" className="h-7 w-auto sm:h-8" />
Expand Down
3 changes: 0 additions & 3 deletions src/utils/browser.ts

This file was deleted.

23 changes: 10 additions & 13 deletions src/utils/useScrollListener.ts
Original file line number Diff line number Diff line change
@@ -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<NodeJS.Timeout | null>(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);
Expand All @@ -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);
}
Expand All @@ -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]);

Expand Down

0 comments on commit f298a98

Please sign in to comment.