WICG / interventions

A place for browsers and web developers to collaborate on user agent interventions.
Other
177 stars 28 forks source link

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

Closed KenjiBaheux closed 2 years ago

KenjiBaheux commented 8 years ago

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:

KenjiBaheux commented 8 years ago

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 commented 8 years ago

(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:

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 commented 7 years ago

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 commented 5 years ago

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 commented 5 years ago

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:

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

clshortfuse commented 5 years ago

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:

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:

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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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

shivanigithub commented 5 years ago

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 commented 5 years ago

@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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

I've transferred this issue to https://github.com/whatwg/html/issues/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.)