Detect UA transitions on same-document navigations
jakearchibald opened this issue · 14 comments
Both Safari iOS and Safari Desktop have a feature where you see a 'preview' of the previous history entry when you drag from the edge (iOS) or two-finger swipe (Desktop). This includes same-document traversals.
out.mp4
safari-desktop.mp4
This causes issues when developers have created their own transition. Demo: https://static-misc-3.glitch.me/basic-navigation-transition/. Here's what happens:
- User is on "state 2".
- User drags from the left, revealing a screenshot of "state 1".
- Navigation commits, but since it's same-document, it's still in "state 1".
- Developer gets a
popstate
event, so they begin a transition from "state 1" to "state 2", meaning it looks like things 'snap back' to "state 2".
out.mp4
This is a problem in the wild: https://twitter.com/ryanflorence/status/1362095580827160578
I propose:
partial interface PopStateEvent {
readonly attribute boolean skipTransition;
}
partial interface NavigateEvent {
readonly attribute boolean skipTransition;
}
Where skipTransition
is true in cases where the browser has already performed some kind of transition, such that an additional developer-controlled transition would be a bad user experience.
The navigation API could have an API to allow the cached screeenshot to persist until the traversal is complete. Maybe the promise returned from intercept
's handler
can serve as that?
cc @domenic for navigation API stuff, and @annevk for Safari behaviour stuff.
The new boolean attribute SGTM. I'd prefer a name which indicates that the browser has already done a visual transition, instead of what the developer should be doing. But other than naming bikeshed, sounds good.
The navigation API could have an API to allow the cached screeenshot to persist until the traversal is complete.
I didn't understand the purpose of this. The cached screenshot is still a UA detail, we don't want to expose anything about that with this API proposal.
The aim is to avoid a flash of previous page state, in case the previous state isn't available synchronously.
Does this not happen in other browsers?
I haven't seen it on browsers outside iOS and Safari on MacOS.
Does this not happen in other browsers?
Chrome on Android is now working on similar features and so this actually affects Chrome as well. Chrome's bug tracker:
Issue 1410585
I'm not sure it's decided that Chrome will so the same effect for same-document navigations.
Here is an explainer summarizing our overall thinking about coordinating between author defined custom transitions and UA transitions. This issue covers one of the 2 API proposals.
Just one edit to the syntax outlined in the first comment about naming:
partial interface PopStateEvent {
readonly attribute boolean hasUAVisualTransition;
}
partial interface NavigateEvent {
readonly attribute boolean hasUAVisualTransition;
}
The sample code showing how authors would use it is here.
One is supposed to use history.scrollRestoration = "manual" if one want to do own scrolling/transition.
Why is that not enough and how does the new proposal work with scrollRestoration?
The fundamental difference between scroll restoration and transitions is that the author can do manual scroll restoration in all cases. So an API which lets the author decide whether the UA or the author will do the scrolling makes sense.
With transitions, while we'd like authors to be able to customize every navigation, there are cases where its not possible. For example, one of the UX we were exploring lets users visualize their navigation history similar to a tab switcher (or an app switcher if you're on a mobile device). With a UI like this, it's not possible to allow the author to customize the transition.
That's why we need a 2 part API for this problem:
- An API which lets the author specify whether they prefer to override a navigation transition.
- An API which informs the author of the UA's decision.
This API is doing 2. We'd like to not block this on 1 since its easier to do first and makes sense as a standalone API. UAs already make the decision for whether to choose UA or author transition which this API communicates to the author.
It also helps browsers innovate in this space. I can see us coming up with new ways/gestures to navigate, in a VR world for example :). And its nice to be able to add browser UX without breaking sites, while we fill the platform gaps to give authors the requisite primitives for customizing new navigation cases whenever possible.
I missed the second part of the question : "how does the new proposal work with scrollRestoration?"
This has no impact on scroll restoration, it continues to work as-is.
The above said, there is a general problem that if the browser is doing a transition, then it will be displaying a cached rendering of the post-navigation state when the navigate/popState event is dispatched. The browser needs to know when to flip from this cached rendering to the live DOM, and the easiest answer is on the next frame after the event is dispatched. This implies that the author needs to synchronously update to the new DOM on the next frame, including updating the scroll offset if they're doing manual scroll restoration.
We could add some async hook for the author to tell the browser when its safe to switch to live DOM for UA transitions. But the problem of not being able to do async DOM updates without displaying the intermediate state to the user is a general issue. ViewTransition introduced a concept of rendering suppression which we could generalize for this, the suggestion came up here. With an API like this, the author can suppress rendering in the navigate
event until the DOM is ready. And the browser flipping to live DOM on the first frame after the navigate
event would just work.
@smaug---- bump. Does the comment above address your questions?
I'm still having trouble to understand how this would work with manual scroll restoration. UA would do some transition but then the web site might still do random things because it is controlling the scrolling. Doesn't that lead to weird behavior?
Has anyone from webkit commented on this proposal?
I'm still having trouble to understand how this would work with manual scroll restoration. UA would do some transition but then the web site might still do random things because it is controlling the scrolling. Doesn't that lead to weird behavior?
Manual scroll restoration is no different from any other change the author does to update the DOM to the post navigation state. As long as the author updates the DOM to the post nav state in the popState/navigate event, it's up to the browser to ensure a seamless switch from the cached to live post navigation DOM.
You can see this feature in action on Safari (mac/iOS) and Chrome (iOS). Feel free to try any edge case you're worried about.
Has anyone from webkit commented on this proposal?