willmcpo / body-scroll-lock

Body scroll locking that just works with everything 😏
MIT License
4.04k stars 339 forks source link

Is there a Safari/WebKit bug for this? #211

Closed foolip closed 3 years ago

foolip commented 3 years ago

I learned about this library as part of my work on https://insights.developer.mozilla.org/reports/mdn-browser-compatibility-report-2020.html, where one developer said this:

What gives me the most headaches is typically scrolling behavior of iOS. If I need to display a modal or something like a typical hamburger menu. I​ t annoys me that I need a JavaScript library just to get this right​, so that if I get a modal, that the background doesn’t scroll on iOS. I think that’s basically the worst issue that you stumble across in almost every project. [...] The goal is always that you lock scrolling completely. There’s a good library for that, it’s not even large, it’s a small JavaScript dependency. But it annoys me that you need these workarounds for doing simple stuff like that​.

Today I took a look at this repo to try to understand what difference between Safari/WebKit and other browsers makes this workaround necessary, but reading the different code paths depending on isIosDevice I'm not sure I understand it.

I don't doubt that this library is needed and gets the job done, but would like to ask what change to WebKit or other browser engines would be required for it to no longer be necessary?

I ask because I'd like to make sure the appropriate bug is filed at https://bugs.webkit.org/, or on Chromium if changes are needed there too.

(I'm on the Google Chrome team, trying to make the web more interoperable so web developers can spend less time on workarounds.)

brunostasse commented 3 years ago

The difference between WebKit on iOS and all other browser engines is that it doesn't allow to reliably prevent body scrolling by setting overflow: hidden to the body, as it should.

This is a very (very) long-standing issue with WebKit on iOS. Setting overflow: hidden to the body used not to prevent body scrolling in any situation before recently (one or two years ago). The situation has now slightly improved, but remains quite unsatisfactory.

Based on my own (not thorough) tests, it now works when:

However, it still does not work when:

It also might not work with some metatags; when the keyboard is displayed; or in in-app browsers.

As you can gather, this is quite a mess. This is why libraries like this one, which use preventDefault() on scroll-related events when necessary are still required and popular. This is far from being a great workaroung though, as they don't perfectly polyfill the overflow: hiddenbehaviour:

There used to be several bugs filled on that issue, today only one remains: https://bugs.webkit.org/show_bug.cgi?id=214781, and does not cover all situations mentioned. The reason why there aren't more filled bugs being: I guess people got tired of filling bugs, testing fixes which only solve small parts of the problem, and arguing with the WebKit team.

foolip commented 3 years ago

Thank you for all the details, @brunostasse, that's great! Sounds like I should test various combinations of overflow: hidden across browsers and see if I can find existing (failing) tests and browser bugs for differences, mostly WebKit bugs that is.

Assuming that overflow: hidden worked perfectly across browsers, would JS still be required to prevent scrolling in the scenarios this library is usually used? Or is there also a CSS solution to this problem that's even further from working across browsers which would be the ultimate fix?

diachedelic commented 3 years ago

@foolip I imagine that overscroll-behavior will be a great solution once widely supported.

brunostasse commented 3 years ago

@foolip There is at least one other case in which you'll find that overflow: hidden is not working properly, that is in Firefox (at least in Android I think) when the page has the viewport metatag user-scalable=0. In that case, body scroll is indeed prevented, but the body is also being scrolled to the top, which is not desired.


Regarding other scenarios where this library might still be useful if overflow: hidden worked perfectly, to my knowledge there is only one: when you want to prevent body scroll initiated only on some elements. For instance, if you have a side menu or a bottom panel displayed only on part of the screen, you don't want scroll initiated inside this element to propagate to the body, BUT, you also don't want the body to be unscrollable if initiated outside of it.

I know of two ways to achieve that with CSS:

I am not aware of all the scroll related specs, so I am not sure if this makes sense, but maybe overscroll-behavior could be made to have effect even for elements with overflow values equal to scroll, auto or hidden, no matter if there is content overflowing or not. Considering the fact that elements with overflow: hidden are still programmatically scrollable, as opposed to those with the values clip or visible, that would make sense to me. That way overscroll-behavior: contain would indeed be a perfect way of preventing body scroll in all scenarios.

ryanbadger commented 3 years ago

iOS seems to support overflow:hidden on body now, can it be added in?

Parth24072001 commented 3 months ago

anyone tell me hoe to fix this bottom scroll for safari IMG-20240509-WA0002