Skip to content

Commit 821187d

Browse files
committed
fix: scrolling performance issue
1 parent 925e4eb commit 821187d

2 files changed

Lines changed: 53 additions & 21 deletions

File tree

components/about/scroll-logos.tsx

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,43 @@ function ScrollLogos() {
99
const scrollContainer = scrollRef.current;
1010

1111
if (!scrollContainer) return;
12-
let currentScrollPosition = 0;
1312

14-
const startScrolling = () => {
15-
const move = () => {
13+
const mediaQuery = typeof window !== 'undefined' && 'matchMedia' in window ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;
14+
if (mediaQuery?.matches) {
15+
scrollContainer.scrollTo(0, 0);
16+
return;
17+
}
18+
19+
let currentScrollPosition = scrollContainer.scrollLeft || 0;
20+
let animationFrameId: number | null = null;
21+
let lastTimestamp = performance.now();
22+
const frameDuration = 30;
23+
24+
const step = (timestamp: number) => {
25+
const elapsed = timestamp - lastTimestamp;
26+
27+
if (elapsed >= frameDuration) {
1628
const totalWidth = scrollContainer.scrollWidth;
1729

18-
currentScrollPosition += 1; // move 1px per interval
30+
currentScrollPosition += 1;
1931
if (currentScrollPosition >= totalWidth / 2) {
20-
currentScrollPosition = 0; // reset to 0 when it reaches the end
32+
currentScrollPosition = 0;
2133
}
2234

2335
scrollContainer.scrollTo(currentScrollPosition, 0);
24-
};
36+
lastTimestamp = timestamp;
37+
}
2538

26-
return setInterval(move, 16); // move every 20ms
39+
animationFrameId = requestAnimationFrame(step);
2740
};
2841

29-
const intervalId = startScrolling();
42+
animationFrameId = requestAnimationFrame(step);
3043

31-
// clear interval on unmount
32-
return () => clearInterval(intervalId);
44+
return () => {
45+
if (animationFrameId !== null) {
46+
cancelAnimationFrame(animationFrameId);
47+
}
48+
};
3349
}, []);
3450

3551
const logos = useMemo(

components/shared/scroll-icons.tsx

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,44 @@ function ScrollIcons() {
1414
const scrollContainer = scrollRef.current;
1515

1616
if (!scrollContainer) return;
17-
let currentScrollPosition = 0;
1817

19-
const startScrolling = () => {
20-
const move = () => {
18+
const mediaQuery = typeof window !== 'undefined' && 'matchMedia' in window ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;
19+
if (mediaQuery?.matches) {
20+
scrollContainer.scrollTo(0, 0);
21+
return;
22+
}
23+
24+
let currentScrollPosition = scrollContainer.scrollLeft || 0;
25+
let animationFrameId: number | null = null;
26+
let lastTimestamp = performance.now();
27+
const frameDuration = isMobile ? 48 : 30; // throttle updates to ~20-30 FPS
28+
29+
const step = (timestamp: number) => {
30+
const elapsed = timestamp - lastTimestamp;
31+
32+
if (elapsed >= frameDuration) {
2133
const totalWidth = scrollContainer.scrollWidth;
2234

23-
currentScrollPosition += 1; // move 1px per interval
35+
currentScrollPosition += 1;
2436
if (currentScrollPosition >= totalWidth / 2) {
25-
currentScrollPosition = 0; // reset to 0 when it reaches the end
37+
currentScrollPosition = 0;
2638
}
2739

2840
scrollContainer.scrollTo(currentScrollPosition, 0);
29-
};
41+
lastTimestamp = timestamp;
42+
}
3043

31-
return setInterval(move, isMobile ? 48 : 20); // faster scrolling on desktop
44+
animationFrameId = requestAnimationFrame(step);
3245
};
3346

34-
const intervalId = startScrolling();
47+
animationFrameId = requestAnimationFrame(step);
3548

36-
// clear interval on unmount
37-
return () => clearInterval(intervalId);
38-
}, []);
49+
return () => {
50+
if (animationFrameId !== null) {
51+
cancelAnimationFrame(animationFrameId);
52+
}
53+
};
54+
}, [isMobile]);
3955
const logos = useMemo(
4056
() => [
4157
...aboutPageConfig.developers.logos,

0 commit comments

Comments
 (0)