diff --git a/src/components/OverlayScrollArea.tsx b/src/components/OverlayScrollArea.tsx index 0b546a5c..30ade1a5 100644 --- a/src/components/OverlayScrollArea.tsx +++ b/src/components/OverlayScrollArea.tsx @@ -60,6 +60,8 @@ export default function OverlayScrollArea({ const perfFlags = usePerfProbeFlags(); const wrapRef = useRef(null); const viewportRef = useRef(null); + /** Coalesce burst scroll events to one thumb update per animation frame. */ + const scrollRecomputeRafRef = useRef(0); const [meta, setMeta] = useState({ thumbH: 0, thumbT: 0, visible: false }); const recompute = useCallback(() => { @@ -71,6 +73,21 @@ export default function OverlayScrollArea({ setMeta(computeOverlayScrollbarThumbMeta(vp, trackH)); }, []); + const scheduleScrollRecompute = useCallback(() => { + if (scrollRecomputeRafRef.current !== 0) return; + scrollRecomputeRafRef.current = requestAnimationFrame(() => { + scrollRecomputeRafRef.current = 0; + recompute(); + }); + }, [recompute]); + + useEffect(() => () => { + if (scrollRecomputeRafRef.current !== 0) { + cancelAnimationFrame(scrollRecomputeRafRef.current); + scrollRecomputeRafRef.current = 0; + } + }, []); + const measureKey = JSON.stringify(measureDeps ?? []); useLayoutEffect(() => { @@ -138,7 +155,7 @@ export default function OverlayScrollArea({ id={viewportId} ref={setViewportNode} className={viewportClass} - onScroll={perfFlags.disableOverlayScrollbars ? undefined : recompute} + onScroll={perfFlags.disableOverlayScrollbars ? undefined : scheduleScrollRecompute} onWheel={viewportOnWheel} onTouchMove={viewportOnTouchMove} > diff --git a/src/styles/components.css b/src/styles/components.css index 2fd21a52..ac2981f7 100644 --- a/src/styles/components.css +++ b/src/styles/components.css @@ -401,6 +401,12 @@ contain-intrinsic-size: 0 220px; } +/* Same wrap as Albums grid; defer layout/paint for off-screen artist tiles (helps scroll on WebKit/Linux). */ +.album-grid-wrap > .artist-card { + content-visibility: auto; + contain-intrinsic-size: 0 220px; +} + @media (min-width: 1024px) { .album-grid-wrap { @@ -420,6 +426,11 @@ contain-intrinsic-size: 0 240px; } +.album-grid .artist-card { + content-visibility: auto; + contain-intrinsic-size: 0 240px; +} + .album-card-more { flex: 0 0 clamp(140px, 15vw, 180px); display: flex;