Skip to content
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

[Slider] Improve touch passive event handling #22269

Merged
merged 8 commits into from
Aug 22, 2020

Conversation

mikhalev-im
Copy link
Contributor

@mikhalev-im mikhalev-im commented Aug 18, 2020

Fixes #13623

Hope I followed all the guides and didn't miss anything codewise, as this is my first-time contribution

@mui-pr-bot
Copy link

mui-pr-bot commented Aug 18, 2020

Details of bundle changes

Generated by 🚫 dangerJS against d32384d

@oliviertassinari oliviertassinari added the component: slider This is the name of the generic UI component, not the React module! label Aug 18, 2020
@oliviertassinari oliviertassinari added the new feature New feature or request label Aug 18, 2020
@oliviertassinari oliviertassinari changed the title [Slider] Improve touch passive event handling (#13623) [Slider] Improve touch passive event handling Aug 18, 2020
@oliviertassinari
Copy link
Member

oliviertassinari commented Aug 19, 2020

Solve the issue:

Capture d’écran 2020-08-19 à 12 19 24

@oliviertassinari
Copy link
Member

The rule from lighthouse: https://web.dev/uses-passive-event-listeners/. For those who wonder why
https://github.com/mui-org/material-ui/blob/776c80b47987d5180362ea613813c0e182e6868e/packages/material-ui/src/Tooltip/Tooltip.js#L427 or https://github.com/mui-org/material-ui/blob/776c80b47987d5180362ea613813c0e182e6868e/packages/material-ui/src/SwipeableDrawer/SwipeableDrawer.js#L495
don't trigger this warning, it's because lighthouse only look at touch start events inside of the document (with synthetic events we benefit from delegation)

We push the discussion further in #20990. At least relying more on passive events is a step in the right direction.

@oliviertassinari
Copy link
Member

With React 17 change of event delegation, I would expect this problem to surface again facebook/react#6436

@oliviertassinari
Copy link
Member

Bingo #22252

Copy link
Member

@eps1lon eps1lon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand this correctly we use a pure CSS solution by default where touchAction: none means scrolling is disabled. However, in iOS this feature isn't supported so we have to fallback to a non-passive scroll listener that calls preventDefault()?

If that is true then I'd make two suggestions:

  1. use feature detection instead of user-agent sniffing
    That way new versions of iOS automatically use the better implementation (no JS) once it supports it. And we don't have to rely on compatibility tables which are only useful as an approximation. I know of at least 2 examples in the past year where they were outdated. I'll try to come up with an example for this. Need to find Safari 12 on iOS first.

  2. Don't check the feature state in the event handler. Seems to me iOS === true implies that the event is cancelable

@eps1lon
Copy link
Member

eps1lon commented Aug 19, 2020

Tested with firefox 51 which does not support touch-action: none according to caniuse. Used a production deploy of https://codesandbox.io/s/zen-fermat-1o2wt?file=/src/App.js available under https://csb-1o2wt-o0qacglln.vercel.app/

let cachedSupportsTouchActionNone;
function doesSupportTouchActionNone() {
  if (cachedSupportsTouchActionNone === undefined) {
    const element = document.createElement("div");
    element.style.touchAction = "none";
    document.body.appendChild(element);
    cachedSupportsTouchActionNone =
      window.getComputedStyle(element).touchAction === "none";
    element.parentElement.removeChild(element);
  }
  return cachedSupportsTouchActionNone;
}

It's a bit more involved but also way more robust. Considering the latest safari on iOS does support touch-action: none and passive event listeners are quite the perf boost I'd say it's worth it.

@oliviertassinari
Copy link
Member

@eps1lon Your assumptions are correct. To answer your points:

  1. I don't know how to feature detect the support of such a feature. I doubt it's possible has it's at the CSS level. Considering that touch action is supported by iOS 13 and that this version has above 80% of market share on iOS, we could drop the iOS check https://www.statista.com/statistics/1118925/mobile-apple-ios-version-share-worldwide/ in the near future.
  2. Checking for .canceable wasn't enough. We get a warning in Chrome if we don't do so. To me, it doesn't make sense.

I have updated the logic with a new commit, to make it cleaner.

@oliviertassinari
Copy link
Member

oliviertassinari commented Aug 19, 2020

are quite the perf boost I'd say it's worth it

I don't follow how you come to this conclusion. From what I understand, there are two major elements that reduce its performance win potential.

  1. the area of the screen: only where the slider is, a fraction on the area of the screen.
  2. the number of events, only one, the touch start.

@@ -618,8 +624,7 @@ const Slider = React.forwardRef(function Slider(props, ref) {
});

const handleTouchStart = useEventCallback((event) => {
if (event.cancelable && iOS) {
// Workaround as Safari has partial support for touchAction: 'none'.
if (!touchActionSupport) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just check event.cancelable? That way we don't accidentally leave this untouch if we change when we add passive listeners or not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We get a warning in Chrome if we don't do so.

document this please

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we should investigate it further. This doesn't seem right.

Copy link
Member

@oliviertassinari oliviertassinari Aug 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we should investigate it further. This doesn't seem right.

Agree, it doesn't seem right, but I don't think that we should care either. Will it make a difference?

@eps1lon
Copy link
Member

eps1lon commented Aug 19, 2020

I don't know how to feature detect the support of such a feature. I doubt it's possible has it's at the CSS level.

I said that I verified it with Firefox 51. Do you have an example where it fails?

@oliviertassinari
Copy link
Member

oliviertassinari commented Aug 19, 2020

I said that I verified it with Firefox 51. Do you have an example where it fails?

Thanks for the example, I haven't tested, it's ingenious. Honestly, I think that we can keep the iOS check, it sounds good enough for the problem. I believe there are no performance concern #22269 (comment), it's more a matter of preparing the drop of Safari < 13 support.

@@ -126,6 +126,23 @@ const axisProps = {

const Identity = (x) => x;

// TODO: remove support for Safari < 13.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside: I really need to get an implementation working with pointer events. With those we don't need touchAction: none if I remember correctly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we need to drop the support of older phones if we move to pointer events?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what phones we're supporting. But even our current browserslist would match

@oliviertassinari oliviertassinari merged commit 2592a60 into mui:next Aug 22, 2020
@oliviertassinari
Copy link
Member

@mikhalev-im Thanks for the help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: slider This is the name of the generic UI component, not the React module! new feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Slider] Improve touch passive event handling
4 participants