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

Touch listeners defaulting to passive #18

Closed
RByers opened this issue Apr 26, 2016 · 128 comments
Closed

Touch listeners defaulting to passive #18

RByers opened this issue Apr 26, 2016 · 128 comments
Assignees

Comments

@RByers
Copy link
Member

RByers commented Apr 26, 2016

Now that we have an API for passive event listeners, chromium wants to experiment with sometimes defaulting listeners into the passive state (in order to get results like this). If we can succeed in making some breaking changes for this, then we'll work with the TECG to explore changes to the TouchEvents spec.

Note that most browsers already have a form of intervention here in terms of a timeout. But this timeout does not follow most of the intervention guidelines and is in some ways the worst of both worlds. The hope here is that we can eliminate the need for such timeouts by replacing it with something that is both more rational/predictable for developers and provides a better user experience.

We only have a skeleton of a concrete proposal so far, but are collecting metrics from the wild to evaluate the tradeoffs of some possible proposals. Chrome 52 includes a flag allows users/developers to opt-in to a couple different modes of passive-by-default touch listeners.

EDIT 2/12/17: See #35 and this post for details of a specific intervention now shipping in Chrome 56. Updated to reflect shift in thinking from "forced" to just "default" (but overridable).

@RByers RByers self-assigned this Apr 26, 2016
@RByers
Copy link
Member Author

RByers commented Apr 26, 2016

/cc @tdresser @dtapuska who are working on the engineering in chromium for this.

@RByers
Copy link
Member Author

RByers commented Apr 26, 2016

Note that we're thinking that this will start by applying only to cases where passive isn't specified like: addEventListener("touchstart", handler). That would then behave differently from addEventListener("touchstart", handler, {passive:false}). But this would be more of a migration strategy / hint than behavior we'd expect to keep long term (i.e. if CNN made their touch listener passive:false for some reason without fixing the jank, we'd still want to intervene on the user's behalf). So I don't think that distinction would ever really belong in the DOM spec. /cc @annevk @smaug---- @jacobrossi, thoughts?

@smaug----
Copy link

If we start doing something like this, then it isn't clear to me at all anymore why we'd need 'passive'.
Especially given that there is touch-action and such.

@RByers
Copy link
Member Author

RByers commented Apr 26, 2016

Interventions are primarily about improving the user experience at the expense of some developer rationality. A core part of the guidelines is that if developers follow best practices, they will never be impacted by an intervention. This lets us generate warnings / metrics around intervention triggering and drive them down as a thing to avoid. We can't do any of that without an explicit API where developers can opt-in in a rational manor to passive behavior.

@RByers
Copy link
Member Author

RByers commented Sep 26, 2016

Quick update:

  • The most promising change here seems to be to treat touch listeners on window, document, document.documentElement and document.body as passive by default (spec issue).
  • Chrome has shipped the above behavior to 50% of dev-channel users and saw a 50% reduction in scroll start time at the 95th and 99th percentiles, without any reports of substantial breakage.

@smaug----
Copy link

Have you considered other options here, since this kind of change would make the platform less coherent internally and would add yet more special cases to the already complicated platform?
Like, a browser could have a "performance hint console" to tell to the web developers that whatever they are doing is probably slowing down ux and what they could do instead is and if they want to keep the existing behavior but don't see the warning again do .

I'm rather worried that if we end up adding more and more "interventions", we end up polluting the platform with tons of small hacks and inconsistencies, and such things tend to beat us later, when designing new APIs or spec'ing how the platform works.

@RByers
Copy link
Member Author

RByers commented Sep 27, 2016

Yeah I'm worried about this too. We've long had devtools features highlighting scroll performance problems, and in general we've found they're helpful for developers motivated around perf, but when our goal is to improve the 95th percentile latency for users they're nearly useless (developers looking at perf in devtools are generally well below the 95th percentile, it's the sites where nobody is even measuring that matter most to the 95th percentile).

Long term ideally I think we'd aim to make touch events universally passive by default (basically the same way pointer events are, but with an opt-out if you really want it). That, I think, would be clean / rational from a web developers perspective. WDYT? Of course we'd need some transition path over many years to avoid breaking the web too badly in order to get there.

@rjgotten
Copy link

rjgotten commented Sep 28, 2016

it's the sites where nobody is even measuring that matter most to the 95th percentile.

And your solution is adding hacks to the browser that affect every website everywhere and which can and do (note the referenced PhotoSwipe issue) suddenly break previously perfectly valid code which is intercepting touch events at the document level for anything as basic as page-wide drag&drop.

Here's a suggestion: put these hijinks behind a switch that devs can turn off with a <meta content="back-the-hell-off"/> tag, so there is an escape hatch until third-party libraries can catch up.

@smaug----
Copy link

The idea here is that web sites could explicitly use non-passive listeners by passing the right kind of dictionary to addEventListener.
But I agree, this kind of changes are a bit web dev hostile, which is why I was wondering if other mechanisms have been investigated to improve the ux of pages. Sounds like no.

@dtapuska
Copy link

The PhotoSwipe code is setup to use PointerEvents but they are using the proprietary detection mechanism so when Chrome ships pointer events (M55) and FireFox does later this year it wouldn't take advantage of them.

meta tags are difficult for libraries to override set. So the escape hatch here is to provide a fully defined value. But really in this case it should be switched to use pointer events as it would be more efficient.

@RByers
Copy link
Member Author

RByers commented Sep 28, 2016

And your solution is adding hacks to the browser that affect every website everywhere and which can and do (note the referenced PhotoSwipe issue) suddenly break previously perfectly valid code which is intercepting touch events at the document level for anything as basic as page-wide drag&drop.

Yep, that's the nature of interventions: make the experience substantially better for a LARGE number of users at the cost of some small compat / developer pain cost. There's definitely a legitimate concern here about striking a good tradeoff, but in general the user experience has gotten so bad on the mobile web (putting the entire platform at such risk of economic collapse) that I don't think anyone involved really believes the right tradeoff is to land entirely on the side of developers over users. Our (Google web platform team's) thinking on that is mostly summarized here and yes it definitely includes that developers should usually have a way to opt-out (as they do in this case).

But note that if you're already following best practices (eg. making your site work correctly with touch on Microsoft Edge) then you'll already have a touch-action: none rule in such case and your site will continue to work fine. Even if you don't, it's likely your site will still work ok (eg. if it's really a full screen drag and drop then the page won't be scrollable). Specific counter examples appreciated, making the ideal tradeoff is challenging.

@RByers
Copy link
Member Author

RByers commented Sep 28, 2016

And just to make sure we're all clear on the benefit - we're talking about giving all users the experience on MANY major websites seen on the right of this video: https://www.youtube.com/watch?v=NPM6172J22g. Given the huge positive response that video has gotten from users, we're willing to accept a little bit of hacks / compat pain here.

@rjgotten
Copy link

rjgotten commented Sep 28, 2016

meta tags are difficult for libraries to override set.

Hence the libraries will have to fix their problems. A meta tag switch would be an escape hatch for developers depending on third-party libraries that have not been updated yet.

developers should usually have a way to opt-out (as they do in this case).

They're effectively stuck until all the libraries their project relies on, update to handle what is essentially a breaking change in their years of handling touch events.

Complex touch event scenarios are a [[censored]] nightmare hellscape. And now you're saddling devs with either switching to a different library (with its own potential weaknesses) or forcing them to dive into the guts of those libraries themselves to sort it out. If you call that a viable opt-out, you're mad.


Besides: do you know what the easiest way is to patch those issues? You override whatever abstraction for addEventListener the library uses to detect passive event listener support and include a passive:false that is hardoced for all events and which gives Chrome the finger. Road of least resistance. Road of least cost. And a road which ends in a status quo that is atleast known to work correctly, even if it performs worse.

Guess what solution companies that are already not interested in performance are going to use?

@tdresser
Copy link

In this case, developers don't need to wait for libraries to update, they can apply touch-action to the parts of their page that should prevent scrolling.

@rjgotten
Copy link

rjgotten commented Oct 26, 2016

In this case, developers don't need to wait for libraries to update, they can apply touch-action to the parts of their page that should prevent scrolling.

In many complex interaction cases touch-action needs to be applied and unapplied dynamically, determined by the user's interaction state with various parts of a UI. That interaction state may well be under the control of a third-party library that is used to render part of the UI; or that implements an abstraction on top of touch events for complex user gestures that a UI requires.

So please explain again why you believe developers wouldn't need to wait for libraries to update, because there certainly are plenty of cases where they will...

@simeydotme
Copy link

Youtube

The Chrome Devtools Console should be renamed to the "Violation Dump"
QA teams questioning all the "violations", and I've noticed absolutely no improvement to my websites, or the websites I visit daily :/

@Rycochet
Copy link

Just of note, as Edge still shows no signs of supporting the options parameter on addEventListener you still need to do browser / feature detection (and since IE will be around for many years that's unlikely to change this decade).

Typescript also only added support for the options parameter in 2.3.1 (microsoft/TypeScript#14188) - so any code from before then would have had to override the argument type to use it.

@patrickkettner
Copy link

Just of note, as Edge still shows no signs of supporting the options parameter on addEventListeneR

We've been shipping this in our insider build for a couple months. Should be in the next stable releaee

@Rycochet
Copy link

@patrickkettner Awesome! :-) Do you know (or can you say) if Edge is adding the passive default value for touch listeners?

@patrickkettner
Copy link

patrickkettner commented Jun 19, 2017 via email

@Rycochet
Copy link

Rycochet commented Jun 19, 2017

In which case - anyone from the Mozilla / Firefox dev teams want to weigh in on here and have all the major browsers doing the same thing so this can get put into the standards and the whole issue closed?

(Just to say, that won't help the thousands of sites that have been broken by this and won't get updated, but will at least get things moving in the future, even if it is just overriding the option by default).

@Rycochet
Copy link

I've noticed that the Verbose warning about passive listeners now turns up on all touch events in Chrome - which results in hundreds of thousands of (normally hidden) warnings before the tab crashes -

[Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive.

image

When the event specifically has {passive:false} added to it then it's a pretty good indication that is not possible. Adding specific CSS to say it won't scroll is not possible as the decision to scroll is made in Javascript on the event itself.

While I still hope that the standards change to fix this bug, these warnings are worse than useless with the sheer amount of spam appearing on even the simplest of web apps...

fgarciajulia added a commit to fgarciajulia/vue-l-carousel that referenced this issue Nov 5, 2017
@allMighto
Copy link

  <a
      href="tel:+xxxxxxxxxx"
    >CALL 6514 9729
  </a>

this code is printing this error on mobile view !

[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080

@jfirebaugh
Copy link

jfirebaugh commented Feb 27, 2018

Starting in iOS 11.3 beta, iOS Safari is shipping with a version of WebKit that defaults touchstart and touchmove event listeners on body, document and window to passive.

Unfortunately, WebKit does not support touch-action: none, so anyone who is relying on that to avoid this intervention will need to apply a second workaround, namely to bind the event with {passive: false} and use preventDefault.

https://bugs.webkit.org/show_bug.cgi?id=175346
https://bugs.webkit.org/show_bug.cgi?id=175869
https://bugs.webkit.org/show_bug.cgi?id=182521

@rjgotten
Copy link

rjgotten commented Feb 27, 2018

@jfirebaugh

I've been waiting for something like this to happen for over a year now. That Apple would at one point copy Google's intervention was a given. That they'd do it without first implementing touch-action is hilarious, and also not entirely unexpected - given their track-record of launching broken or breaking web features.

Wonder what the "You just need to add touch-action:none to fix it"-crowd is going to say now.

@RByers
Copy link
Member Author

RByers commented Mar 19, 2018

Yeah this is unfortunate. I'm asking Apple to reconsider shipping the intervention here.

Wonder what the "You just need to add touch-action:none to fix it"-crowd is going to say now.

The "right" thing to say would be to show the ~20 lines of code necessary to properly feature detect touch-action and EventListenerOptions to set passive:false when the latter is supported without the former. But even I don't believe most people are likely to do that (or at least, those that are don't need my help showing how to do it). Despite the drawbacks, perhaps we should just encourage the simple one-line UserAgent check to ensure Safari always gets passive:false (regardless of whether they support touch-action in the future)?

@rjgotten
Copy link

rjgotten commented Mar 19, 2018

@RByers

If you're talking a one-size-fits-all cure-all patch that can be injected from author-land, and which respects the intervention (rather than nuke it altogether by forcing passive:false as a universal default) ---

then I think you should detect support for the touch-action CSS property, rather than sniff for Safari's UA.

For any browsers that does not support touch-action, you'd want the sane default to be the 'oldskool' behavior.

Conversely any browser which does support touch-action can set its interactions up properly with that.
Well; usually anyway.

Luckily, for the really complicated edge cases where passive:false is absolutely necessary, such a polyfill would still patch addEventListener to universally accept EventListenerOptions arguments. It would just silently drop the passive flag and translate the capture flag to a boolean argument when EventListenerOptions are not supported. No harm done.

@jfirebaugh
Copy link

But even I don't believe most people are likely to do that

From the perspective of a web developer responsible for a widely deployed library that has been broken twice now by this intervention: no, they aren't. The next version of Mapbox GL JS will be forcing passive: false and preventing default when it needs to, performance be damned. I expect other affected developers will do the same. This whole episode has been extremely frustrating from beginning to end, and I will do whatever it takes to prevent my software being broken again, even if that doesn't have ideal performance characteristics. Keeping my software actually functioning will always take precedence over performance, and the browser vendors have been quite inconsiderate of my needs, so I don't see any reason to bend over backwards with a bunch of feature detection, especially given that a previously-recommended solution has now been broken by a subsequent browser release.

@RByers: I know you have lots of metrics supposedly showing the advantages of this intervention. How are you measuring the costs? I see little or no consideration or discussion of costs in the metrics doc or blog post. However, between this issue, the blog post comments, this issue, and various other venues, there are probably hundreds of developers responding negatively to this intervention. Do you weigh that response in your decision at all? Is there any amount of developer anti-goodwill that would convince you that an intervention is a bad idea?

I've tried to keep this comment civil, but I have to admit it has been difficult. I'm really pissed at the decisions the Chrome and WebKit teams have made on this issue. I hope they reflect on the real difficulties and frustrations this intervention created for developers and end users, and reconsider making similar breaking changes to the web in the future.

@jfirebaugh
Copy link

PSA to fellow developers trying to clean up after this -- WebKit has several related bugs that you'll also need to work around:

@mike-marcacci
Copy link

mike-marcacci commented Apr 12, 2018

Haha, I guess things really are cyclical :) perhaps Chrome should have multiple "rendering modes" – one that follows web standards, and another with potentially breaking interventions... and we can call the latter "quirks mode" for fun.

But seriously, it's not lost on me that a major reason for jQuery's ubiquity is that it unified the behavior of browsers, which had subtle differences in the way they approached features like event propagation.

@dtapuska
Copy link

@drbcode This issue is for touch event listeners as passive. Do you really see that much touch usage on desktop? Mobile primarily is where touch usage is high and it doesn't support extensions.

Perhaps you are referring to #64 intervention instead?

@ghost
Copy link

ghost commented Apr 24, 2019

@dtapuska yes, the comment that I made did not belong here so I added it on #64 instead for a proper context.

@ghost
Copy link

ghost commented Apr 24, 2019

@dtapuska chromebooks have touch screens and some extensions and apps require touch events to work properly.

chrome apps and extensions should be considered as well before implementing an intervention to get more accurate statistics.

@ghost
Copy link

ghost commented Apr 24, 2019

@dtapuska Yandex mobile browser supports chrome extensions and many people use it, it also got affected by above intervention.

Our analytics show that at least 5-10% of our users use our chrome extension on a mobile device, especially in asian countries.

Yandex browser is very popular because they support chrome extensions.

Now to support all the above our team has to spend a lot of effort to test whether all the events work as they should.

@johannhof
Copy link
Member

(As noted in #72, we intend to archive this repository and are thus triaging and resolving all open issues)

I've closed out #35 and #64 as they're being followed up elsewhere. Given the coming archival of this repository I think it's better to track this overall effort somewhere else, such as in a separate explainer repo. I'm reaching out to the team that's working on related things on Chrome side to see if they're interested in pursuing that.

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