-
-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automatic browser scrolling corrupts router scroll history #707
Comments
Interesting! I can't repro this with |
This is how I tried to fix this for I wonder how |
I suggest we take pragmatic approach and do the following:
This means we will only restore scroll on Back, but will always scroll to top on Forward. I think it's a sensible compromise, and I think it doesn't make UX worse in any meaningful way. This would involve changing |
Thank you for bringing this up.
Yes. |
Oh, you're right. Apparently, popstate and hashchange are more different than I thought. So I think the situation is as follows:
😢
Well, it does fix the case I described. I'm not convinced it's a good solution though, since it will not record any position changes that aren't followed by a push. Take this case for example:
(Same as original, but now scrolling on second page) |
What do you define as “failing” in this case? What I see is, after clicking Forward, scroll position is reset to top. I don't think this is a huge issue and it's an intentional tradeoff we can make. The biggest bummer would be losing Back scroll position. IMO we can afford always scrolling to top on Forward because it doesn't degrade usability as much, but at least gives us consistent behavior without clearly bad behavior (such as scrolling one page to a saved position of another page). |
It can also be inconsistent with "back" when scrolling on a page visited before, clicking forward, and then back again. I can't think of a real-world scenario where I would this though, so perhaps you're right about this being the solution to go with. |
Can you put this into reproducible steps? I'm trying to imagine this but I can't see it going wrong yet. |
Result: Scrolls to top (or whatever scroll position on 2)) Basically it goes wrong whenever you scroll on a page, leave it without push (without clicking on a link) and then come back to it again (via browser back, forward or whatever). |
I see now.. This isn't a big problem IMO but it isn't very nice either. |
OK, I'll give this and #690 more thought on Monday and try to come up with something to fix both. |
#690 is definitely unrelated. TLDR: We can only reliably record scroll position (so we can later restore it) after user-initiated transition like Therefore I suggest we merge #708. This gives us consistent "scroll to top" on Forward instead of buggy "try to restore something I haven't actually memorized correctly" behavior we have now. |
We can't reliably restore scroll position on Forward due to browser differences and incompatibilities. Instead, we will only restore previous scroll position when user presses Back, and scroll to top on Forward. Fixes remix-run#707.
Thank you for raising this again. |
@gaearon I am working on a small new addition to History API (shipping in chrome 46) which allows web apps to opt out of browser's default scroll restoration. I think it can help resolve some of the scroll restoration issues you were dealing with. I appreciate any feedback you may have given your experience working around these issues. |
@majido i was still having some issues with this, and |
@VonD that is great to hear. Just note that at the moment |
As far as I can tell the implementation of the scrolling behaviors is flawed. But first of all, some steps to reproduce:
After 5), the expected behavior would be to scroll to the top again. Instead, the router will scroll to the position set in 2).
Some console.logs to understand what's going on (Chrome):
The problem is that browsers (at least Firefox and Chrome) will restore their own recorded scroll positions before triggering any events (I believe this is the same for hashchange and popstate), causing the router to store these newly set positions for the previous path. (Things are even worse if you render asynchronously..)
Some thoughts about solving this problem
Since there's no "beforepopstate", the first workaround that occurred to me was to listen to the scroll event and store from there (instead of on dispatch). Unfortunately, browsers will trigger the scroll event themselves after back button navigation and it seems there is no reasonable way to distinguish them from user-initiated scroll events.
So I thought about simply ignoring scroll events for a short time after popstate. Problem with that is that Firefox triggers the scroll event even before popstate. Chrome, for comparison, triggers it afterwards, but restores the scroll position beforehand, and it seems to back off if the scroll position was manually set before popstate finishes (hence there's only one scroll event after back/foward in the above log).
Those problems made me think that maybe the router should not do anything on popstate events, and people should make sure to fully restore content synchronously (at least after popstate). Sadly, Firefox doesn't play along: since it restores the scroll position before popstate, and apparently doesn't do anything afterwards, it will clamp scroll positions to the previous/current page size, i.e. when navigating from a small to a taller page, it will not scroll beyond the small page's height.
Is this really such a mess? Hopefully I'm missing something here.
The text was updated successfully, but these errors were encountered: