Closed foolip closed 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: hidden
behaviour:
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.
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?
@foolip I imagine that overscroll-behavior
will be a great solution once widely supported.
@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:
you can set overflow: hidden
on mouseenter/touchstart on this element, and remove it on mouseleave/touchend. While this works well in Firefox and WebKit (in the case where overflow: hidden
does prevent body scrolling), it doesn't work properly in Chromium on touch devices (Android & Windows). I don't think we can say that FF and WebKit are right and Chromium wrong in behaving like that, as I don't think what should happen in that case is spec'ed anywhere.
Another way of handling this is using overscroll-behavior: contain
, as mentioned by @diachedelic. This is again not a silver bullet at the moment for two reasons though:
overscroll-behavior: contain
, and then scroll immediately the body, the body doesn't get scrolled, instead you keep scrolling the container. This can be mitigated by only applying it on mouseenter/touchstart and removed on mouseleave/touchend.overflow
property set to either auto
or scroll
. If you want to prevent body scroll while scrolling over an element that is not scrollable, then it won't work, you'll be scrolling the body.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.
iOS seems to support overflow:hidden on body now, can it be added in?
anyone tell me hoe to fix this bottom scroll for safari
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:
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.)