Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Annoying user experience on back navigation due to dummy fast-forwarding history entries #21

Closed
KenjiBaheux opened this issue Jun 2, 2016 · 19 comments

Comments

@KenjiBaheux
Copy link
Collaborator

KenjiBaheux commented Jun 2, 2016

We've observed websites abusing (or misusing) History.

Typically, the History get stuffed with multiple dummy entries that fast-forward the user back to the page they wanted to leave.

Getting back to the desired history entry is extremely hard:

  • Because of the instant fast-fowarding nature of the dummy history entries, the user can't wait for a visual confirmation to know when to stop hitting the back button.
  • As a result, the user either overshoot or undershoot its destination resulting in guaranteed frustration.
@KenjiBaheux
Copy link
Collaborator Author

On the Chrome team, we believe that this could be fixed by changing the rules for how an entry gets added to the back/forward history. In particular, we think that entries that didn't have any user gesture should not be allowed.

@domenic
Copy link
Collaborator

domenic commented Jun 6, 2016

(Relaying some previously-internal discussions to this public tracker)

In particular, we think that entries that didn't have any user gesture should not be allowed.

This is a very subtle criterion to define. In particular, if we try to reuse HTML's triggered by user activation (even with some fixes), this will fail. For example, if the spec is that upon navigation, you remove the previous history entry if no user activation occurred, then this means pressing the back button, then the forward button, will wipe out the history entry (since no user activation was encountered), so next time you press the back button, that page would be "missing". @ojanvafai suggested that we'd also include clicking on the forward button as a user gesture, but this seems strange and a bit wack-a-mole to me. (E.g., what about manually entering a new URL in the address bar? Clicking on a bookmark? Etc.)

Additionally, the user-gesture test, even if we expand it to include everything that should "intuitively" work, prohibits some use cases:

  • Auto-turning pages in a book
  • An auto-advancing timed presentation
  • A slideshow
  • (More esoteric) a puzzle game that advances you when you mouseover a certain hidden region of the page, assuming mouseover isn't defined as triggering a user gesture.

In response to these use cases, @KenjiBaheux suggested perhaps scoping the intervention down to remove history entries for pages that insta-navigate you away, instead of basing it on a user-gesture test. So something like: if the navigation occurs within 500 ms (?) of the previous navigation, and it was initiated by page script instead of by the user, then discard the history entry.

Personally this sounds more in line to me with the problems I encounter, which is mostly pages which use poorly-done script-initiated redirects and break my back button since I can't press back twice fast enough.

@natechapin
Copy link

I've got an experiment for this idea behind a flag in chromium. I'm going to be updating it to allow a document that has received a user gesture to create as many history entries as desired (the previous experiment was more restrictive).

Any navigation that is triggered by user interaction with browser UI will always be eligible for a history entry.

@saschanaz
Copy link

saschanaz commented Sep 29, 2018

Some websites are now starting to abuse history entries to insert ads.

On your phone:

  1. Access https://t.co/ll06l1RE9I (t.co redirection is a required condition to repro)
  2. The newly opened page creates history entry which inserts ads.

More examples:

@shivanigithub
Copy link

The latest thinking on this issue is:

If there is no user gesture on a document ever (or possibly on the eTLD+1 to make it less restrictive), and it did a client side redirect, then do the following:

  • Mark the redirecting page's entry in the back list such that it gets skipped on browser's back button click.
  • Note that this will not impact History.back() API.

This should also work with examples given in Domenic's comment above like auto book readers/slide shows, because:

  • They would normally have had at least one user gesture to begin the reading/slideshow, or
  • They would have a custom back/forward UI based on history API

@clshortfuse
Copy link

clshortfuse commented Dec 18, 2018

If there is no user gesture on a document ever (or possibly on the eTLD+1 to make it less restrictive),

This seems to put at ease my worries. I have two worries:

  • Using 'back' to close popups (like dialog and menus) on Android devices.

This is actually in part of the History API spec.

An example of the latter would be something like keeping track of the precise coordinate from which a pop-up div was made to animate, so that if the user goes back, it can be made to animate to the same location.

I'd worry if that pop-up wasn't introduced with a user-interaction, perhaps via a timer, then back would back out of the entire site, and not just close the dialog. On PWAs using standalone display configuration, that would close the entire app.

The second worry is really more of a "hack", but something still used:

  • Listening for popstate in PWAs to intercept an app-close event.

On PWAs, in order to handle when a user wants to quit, a pushstate during init is used to give it a single history buffer and then catch the popstate, before the app closes (and quite possibly prevent it). It's more useful on Safari Mobile since iOS will kill the page and javascript completely when it's not in the foreground (Chrome on Android doesn't do this).

I think excusing PWAs in standalone from this behavior is something to consider.

@domenic
Copy link
Collaborator

domenic commented Dec 19, 2018

This should also work with examples given in Domenic's comment above like auto book readers/slide shows, because:

  • They would normally have had at least one user gesture to begin the reading/slideshow, or

This is not true if it auto-advances to a different document. I.e., this criterion only works for single-page apps.

Right?

@shivanigithub
Copy link

This should also work with examples given in Domenic's comment above like auto book readers/slide shows, because:

  • They would normally have had at least one user gesture to begin the reading/slideshow, or

This is not true if it auto-advances to a different document. I.e., this criterion only works for single-page apps.

Right?

That's right. The latest thinking around this is that there should have been a user gesture on that page before it redirects/ adds a history entry for it to be considered for back button navigations.
So for the auto book reader case, assumption is that it would have its own back/forward UI based on history API for it to work seamlessly even with the intervention.

@domenic
Copy link
Collaborator

domenic commented Dec 19, 2018

Sure, a site can always duplicate browser UI. But no existing sites will, because until this change it's worked well for them.

@shivanigithub
Copy link

If there is no user gesture on a document ever (or possibly on the eTLD+1 to make it less restrictive),

This seems to put at ease my worries. I have two worries:

  • Using 'back' to close popups (like dialog and menus) on Android devices.

This is actually in part of the History API spec.

An example of the latter would be something like keeping track of the precise coordinate from which a pop-up div was made to animate, so that if the user goes back, it can be made to animate to the same location.

I'd worry if that pop-up wasn't introduced with a user-interaction, perhaps via a timer, then back would back out of the entire site, and not just close the dialog. On PWAs using standalone display configuration, that would close the entire app.

The second worry is really more of a "hack", but something still used:

  • Listening for popstate in PWAs to intercept an app-close event.

On PWAs, in order to handle when a user wants to quit, a pushstate during init is used to give it a single history buffer and then catch the popstate, before the app closes (and quite possibly prevent it). It's more useful on Safari Mobile since iOS will kill the page and javascript completely when it's not in the foreground (Chrome on Android doesn't do this).

I think excusing PWAs in standalone from this behavior is something to consider.

Thanks for raising these concerns.
Note that the dialog does not have to be a result of a user gesture. If the page has had a user gesture at any time before the dialog was opened, that page would not be skipped on back button.

For the pushstate/popstate use case, the history entry added via pushstate will itself not be skipped, rather the entry that added it is the one that's marked to be skipped if it did not have any user gesture before adding another entry. Does that solve the issue?

@clshortfuse
Copy link

clshortfuse commented Dec 19, 2018

@shivanigithub Not entirely, but if that's the new behavior, I'd have to make some considerations with on-launch dialogs.

For example, let's say a PWA starts up and brings up a dialog. The dialog could be a "changelog" or a "What's new" or something like to that effect. The user may want to press Back on their Android device because that's how they generally close dialogs. But, because there was no user gesture, and that Back gesture was the first one, instead of closing the dialog, it would actually close the entire application (the default action on Back presses on PWA).

Another example would be an app logging in to a server on launch after it's already cached authentication from a previous session. A spinner shows and then, it can't connect to the server. From there, a dialog popup would appear showing the connection error and possible reason. Again, pressing back here would close out the app.

It's kinda why I would think PWAs in display:standalone would need some sort of exception. For normal web browsers, you can tap forward again, but standalone PWAs don't have user interface.

@jkarlin
Copy link

jkarlin commented Dec 20, 2018

It's unclear to the user today what pressing the back button will do on a page. Pressing back might close the dialog, it might close the tab, or it might even do something completely different. So while I agree this changes existing behavior I'm not sure that users are any worse off for it.

The clear advantage of Shivani's proposal is that the back button will become deterministic to the user, in a way that I think they'll intuitively understand. The back button will return to the last page the user interacted with.

@domenic
Copy link
Collaborator

domenic commented Dec 20, 2018

I was with you, until you said

The clear advantage of Shivani's proposal is that the back button will become deterministic to the user, in a way that I think they'll intuitively understand. The back button will return to the last page the user interacted with.

That won't be true still, right? It will just return to the last pushState-d entry the user interacted with, which could have no visual change at all.

@jkarlin
Copy link

jkarlin commented Dec 20, 2018

That's a fair point, it'll navigate to the page or history entry added by the page the user last interacted with.

I'd still argue this becomes much more deterministic to the user, but not perfectly so.

@ghost
Copy link

ghost commented Oct 24, 2021

Hello guys, I know this is an ongoing task to add to Chrome itself. However I have a question, anyone has any idea to detect (or measure) multiple redirects in JavaScript code?
Or if there is a lighthouse measure for this, or even better a custom metric
I have a metric implemented in JavaScript that scans a page's code and would say if the page has many annoying redirects.
Thanks !

@ghost
Copy link

ghost commented Oct 24, 2021

meanwhile, what is the status of this in Chrome ? anyone knows ? as I couldn't find the flag: enable-history-manipulation-intervention mentioned here

@shivanigithub
Copy link

meanwhile, what is the status of this in Chrome ? anyone knows ? as I couldn't find the flag: enable-history-manipulation-intervention mentioned here

The intervention is enabled by default in Chrome.

@johannhof
Copy link
Member

johannhof commented Feb 10, 2022

See https://twitter.com/Paul_Kinlan/status/1491673376066347013, there seems to be a workaround to the intervention applied in Chrome. There's an unshipped implementation of this in Firefox as well, which doesn't seem affected in my testing.

I think there's value in getting this intervention standardized to give browsers more guidance on how to prevent this.

@domenic
Copy link
Collaborator

domenic commented Apr 18, 2022

I've transferred this issue to whatwg/html#7832, which outlines the state of things and the tradeoffs of specifying vs. not-specifying this. (TLDR it seems worth specifying, even though it's a bit unconventional to specify user agent UI in this way.)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants