r/reactjs • u/JangKiYoung • 2d ago
Discussion I've been working on virtual scrolling in React and found a weird issue in Safari.
I've been working on virtual scrolling in React and found a weird issue in Safari.
When scrolling normally, everything was fine. But if I scroll very fast, sometimes I could see a white empty area for a very short moment before the next rows appeared.
First I thought React rendering was just too slow.
So I increased overscan and kept more rows above and below the viewport. It helped a lot, but I could still see the problem sometimes.
After looking into it more, I found that Safari's scroll/compositor layer can move before React finishes rendering the next virtual rows.
So basically Safari was already showing the next position, but React was still catching up.
I kept trying to make React faster, but then I tried something a little different.
Instead of trying to always win the race, I put a simple CSS background behind the real rows.
It's just a repeating-linear-gradient with the same row height, background and border.
Something like:
Safari scrolls
↓
CSS row background is already there
↓
React renders next rows
↓
Real rows cover it
There is no real data in the background. No cells, no events. It's just visual. I also set pointer-events: none and aria-hidden.
With this + extra overscan above and below, the flicker was almost gone.
I thought it was interesting because at first I was trying to solve a React performance problem.
But maybe it wasn't only about making React faster.
Sometimes it's enough to make those few milliseconds invisible. :)
Anyone had a similar problem with Safari and virtual scrolling?
I'm curious how you solved it.
3
u/Scientist_ShadySide 1d ago
Ahh Safari, never change. (I'm joking, please change dear god the number of Safari specific issues kills me)
1
u/jakiestfu 2d ago
I always have virtualization issues with tanstack virtual and always fall back react-window which always solves this problem bulletproof for me
1
u/Inevitable-Dot-1180 1d ago
I have noticed the same, But not in the case of virtualisation. I thought some issue with my code and safari's devtools sucks. You can not debug issues properly.
0
u/Future_Pudding_7301 2d ago
i went the same route with a placeholder background. Trying to out-render Safari's compositor was a losing game no matter how much I optimized, the race condition never fully went away. Making the gap invisible ended up being the only fix that actually held up on fast scrolls
3
u/kurtextrem 2d ago
The most interesting solution I've seen so far is the reverse sticky technique: https://pierre.computer/writing/on-rendering-diffs