-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Specify back button history-entry skipping? #7832
Comments
Hi Domenic, we've run into an issue with |
Not sure where to mention this, but I think it is also confusing that the context menu Back does not skip the skippable history entries the same way the toolbar back button does, which in my case causes my mouse button and backspace extension to behave differently as well - they apparently emulate the context menu back. |
This imports much of the specification from https://github.com/WICG/navigation-api/blob/91c2e7f959418d71e26e5b9a6723fed2944001d9/spec.bs. It includes some fixes and renamings, as well as a lot of rearranging to flow better, but the feature set is the same. In addition to the new "navigation API" section under "APIs related to navigation and session history", this makes the following changes to integrate the navigation API: * Introduces the NavigationHistoryBehavior enum, as a superset of the "history handling" specification type. This includes an "auto" value to reflect that existing entry points will sometimes default to "replace" instead of "push". The navigation API allows overriding that auto behavior in some circumstances by explicitly supplying "push". (But in some cases, i.e., the initial about:blank or javascript: URLs, this is still not allowed.) * Introduces the concept of "user navigation involvement". This will be helpful for solving issues such as w3c/webappsec-fetch-metadata#71. * Introduces the concept of "history-action user activation", which is a separate type of user activation meant to be used specifically to prevent back button tracking. It has no associated timeout (unlike transient activation), but can be flipped to false (unlike sticky activation). It is used by the navigation API to prevent calling navigateEvent.preventDefault() on two traversals in a row without intervening user activation. It is likely also to be useful for issues such as #7832. * The activation behavior for <a> and <area> elements is made more rigorous and consolidated into one place, so that we can hook into it appropriately to fire navigate events. * Some surgery was needed on "apply the history step". The result is that it now has slightly more parameters, but also several wrapper algorithms which take care of setting up those parameters correctly for the cases of: navigable creation/destruction, push/replace, reload, and traverse. It also returns a value indicating if the application of the history step was canceled, and if so, how; this is used to give informative errors as return values of navigation.traverseTo(). * The "check if unloading is user-canceled" algorithm has become "check if unloading is canceled", as it now handles firing a possibly-cancelable navigate event at the top-level traversable. Other changes scattered throughout are mostly integrating appropriate calls to the navigation API as necessary, especially to fire navigate events.
This imports much of the specification from https://github.com/WICG/navigation-api/blob/91c2e7f959418d71e26e5b9a6723fed2944001d9/spec.bs. It includes some fixes and renamings, as well as a lot of rearranging to flow better, but the feature set is the same. In addition to the new "navigation API" section under "APIs related to navigation and session history", this makes the following changes to integrate the navigation API: * Introduces the NavigationHistoryBehavior enum, as a superset of the "history handling" specification type. This includes an "auto" value to reflect that existing entry points will sometimes default to "replace" instead of "push". The navigation API allows overriding that auto behavior in some circumstances by explicitly supplying "push". (But in some cases, i.e., the initial about:blank or javascript: URLs, this is still not allowed.) * Introduces the concept of "user navigation involvement". This will be helpful for solving issues such as w3c/webappsec-fetch-metadata#71. * Introduces the concept of "history-action user activation", which is a separate type of user activation meant to be used specifically to prevent back button tracking. It has no associated timeout (unlike transient activation), but can be flipped to false (unlike sticky activation). It is used by the navigation API to prevent calling navigateEvent.preventDefault() on two traversals in a row without intervening user activation. It is likely also to be useful for issues such as whatwg#7832. * The activation behavior for <a> and <area> elements is made more rigorous and consolidated into one place, so that we can hook into it appropriately to fire navigate events. * Some surgery was needed on "apply the history step". The result is that it now has slightly more parameters, but also several wrapper algorithms which take care of setting up those parameters correctly for the cases of: navigable creation/destruction, push/replace, reload, and traverse. It also returns a value indicating if the application of the history step was canceled, and if so, how; this is used to give informative errors as return values of navigation.traverseTo(). * The "check if unloading is user-canceled" algorithm has become "check if unloading is canceled", as it now handles firing a possibly-cancelable navigate event at the top-level traversable. Other changes scattered throughout are mostly integrating appropriate calls to the navigation API as necessary, especially to fire navigate events.
This imports much of the specification from https://github.com/WICG/navigation-api/blob/91c2e7f959418d71e26e5b9a6723fed2944001d9/spec.bs. It includes some fixes and renamings, as well as a lot of rearranging to flow better, but the feature set is the same. In addition to the new "navigation API" section under "APIs related to navigation and session history", this makes the following changes to integrate the navigation API: * Introduces the NavigationHistoryBehavior enum, as a superset of the "history handling" specification type. This includes an "auto" value to reflect that existing entry points will sometimes default to "replace" instead of "push". The navigation API allows overriding that auto behavior in some circumstances by explicitly supplying "push". (But in some cases, i.e., the initial about:blank or javascript: URLs, this is still not allowed.) * Introduces the concept of "user navigation involvement". This will be helpful for solving issues such as w3c/webappsec-fetch-metadata#71. * Introduces the concept of "history-action user activation", which is a separate type of user activation meant to be used specifically to prevent back button tracking. It has no associated timeout (unlike transient activation), but can be flipped to false (unlike sticky activation). It is used by the navigation API to prevent calling navigateEvent.preventDefault() on two traversals in a row without intervening user activation. It is likely also to be useful for issues such as whatwg#7832. * The activation behavior for <a> and <area> elements is made more rigorous and consolidated into one place, so that we can hook into it appropriately to fire navigate events. * Some surgery was needed on "apply the history step". The result is that it now has slightly more parameters, but also several wrapper algorithms which take care of setting up those parameters correctly for the cases of: navigable creation/destruction, push/replace, reload, and traverse. It also returns a value indicating if the application of the history step was canceled, and if so, how; this is used to give informative errors as return values of navigation.traverseTo(). * The "check if unloading is user-canceled" algorithm has become "check if unloading is canceled", as it now handles firing a possibly-cancelable navigate event at the top-level traversable. Other changes scattered throughout are mostly integrating appropriate calls to the navigation API as necessary, especially to fire navigate events.
See: whatwg/html#7832 Safari does history-entry skipping, which breaks back/forward buttons even though it works just fine on Firefox.
@domenic what do you think of a permissions API to allow an app to manipulate history entries in a 'non-skippable' way. The app would use the API and the user would be asked for permission right before the browser decides that some entry should be skipped and if the user provides the permission then the browser entries are not skipped anymore. I described other options as well here: https://issues.chromium.org/issues/330744614#comment20 |
I don't think this is something most browser UI teams would be interested in bothering the user about. The bar for a new permission is very high and needs to be something easily understood, like "microphone" or "camera" or "geolocation". |
@domenic I don't know if this is the right place to comment on this/ask about it. If not, feel free to remove my comment. I came across this issue after wanting to trigger "pushState" on different sections on my website/app while the user is scrolling through (with the ability to switch back and forth via "popstate" of course). The App isn't using the default scrolling, but rather using the "wheel" event to add special behaviour. Is it planned to consider "scroll" or "wheel" events as user actions too? I understand that "invoked in succession", these events could be used to push a lot of states to the history. Would something like a timeout or filter mechanism work here? So rules like: "The scroll event triggering the history push has to be one viewport apart from each other"? I read some comments in the google groups, but maybe I'm missing something that's fundamental here. It's working in Firefox for me right now, but I also don't know if they have a filter mechanism or special rules to prevent history spam. Also just out of curiosity, would a click event be "tracked"? Lets say I click a button and on that click it triggers another button click programatically (with e.g. |
Per WICG/interventions#21, some browsers have implemented a heuristic where pressing the back button skips certain entries in the joint session history. Generally, these are entries where there is no user interaction. The intent is to avoid "back trapping", e.g. if you arrive on a malicious site which does
history.pushState()
10 times, this makes it hard to escape the site by pressing the back button.Notably, this is different than ignoring the
history.pushState()
calls entirely (which is explicitly allowed). The joint session history entries still exist from the page's point of view: e.g.,history.length
still increases, andhistory.back()
still goes back to them. But the user pressing the back button will do the equivalent ofhistory.go(-11)
or similar, instead ofhistory.go(-1)
.The current HTML Standard sort of allows this:
... but sort of doesn't:
So at a minimum we should make it clearer that mapping the user expression to the delta might involve such considerations.
But we should probably go further than that. We should probably give more detail on which entries, exactly, will be skipped. Otherwise there are problematic interop problems, where e.g. pressing back will skip a history entry in one browser, and sites depend on it, but in other browsers that entry will not be skipped, leading to an inadvertent bad user experience.
@johannhof has mentioned that reverse-engineering Chromium's logic was a pain for Firefox (and still not shipped). And @miketaylr points out that there are many cases of "back button works in Chrome but not Firefox" bugs; my suspicion is that many of these are due to this issue (although others may be due to other history interop problems).
So even though this part of the web platform, dealing with how you translate user gestures on browser UI into web page actions, is traditionally outside the bounds of specs, in this case I think working on a specification for interoperable behavior would be appreciated. (As a compromise, I think the end result would be mostly "should"s, not "must"s.)
The bad news is that the heuristics here are still evolving. E.g. Chromium has some known bugs in our back-trapping prevention, which @shivanigithub and @creis have been looking at. So it's not even clear whether any browser has an implementation stable enough to spec. Maybe we can try to spec what we have, with the understanding that it will probably continue evolving? I just want to make sure we don't freeze this mapping in stone too early, by specifying it.
As part of this work we may also want to try coming up with more interoperable heuristics for ignoring
pushState()
/replaceState()
calls, since that has similar user-facing effects. As introduced in #999, the spec just says "Optionally, return" with no guidance.The text was updated successfully, but these errors were encountered: