body-scroll-lock icon indicating copy to clipboard operation
body-scroll-lock copied to clipboard

Scroll doesn't work on IOS

Open carpben opened this issue 5 years ago • 12 comments

For some reason Scroll doesn't work in modals on IOS. It works well, on other platforms. To view this issue:

  1. Visit https://www.givingway.com/search.give?searchMode=online on an iphone.
  2. Open the tasks filter.
  3. Try to scroll the screen.

Files in production include source-maps. Specifically visit image I tried locally adding "overflow-y: scroll; -webkit-overflow-scrolling: touch;" but the issue persists.

carpben avatar Apr 10 '19 20:04 carpben

Hmm I am also having an issue on my iPad. However the demo at https://bodyscrolllock.now.sh works fine on the iPad too. Could there be a different implementation than the default?

kemalcany avatar Apr 11 '19 11:04 kemalcany

After testing and playing with the functions for a few hours on various platforms, there is no problem with the library, but how I was using it.

I think the documentation could be improved. Specifically, that the element we would like to allow scroll on, is the same element we should pass to disableBodyScroll (and not a parent of that element) and on which we should apply the following css:

    overflow-y: autp; 
    -webkit-overflow-scrolling: touch;  

As a more reusable solution I created the following component (Written in Typescript, using an Emotion Styled component):

// ScrollBoxW.tsx
import {css} from "react-emotion" // Css in JS library
import { IStyledComponentProps } from "../types" 
import Box from "./Box" // an Emotion Styled div Component
import { getElementFromRef } from "../tools"

const style = css`
	label: scroll-box;
	overflow-y: auto;
	-webkit-overflow-scrolling: touch;  
`

class ScrollBoxW extends React.Component<IStyledComponentProps, {}> {
	public allowScrollRef: React.RefObject<HTMLElement> = React.createRef()

	public componentDidMount = () => {
		disableBodyScroll(getElementFromRef(this.allowScrollRef), {
			reserveScrollBarGap: true,
		})
	}

	public componentWillUnmount = () => {
		clearAllBodyScrollLocks()
	}

	public render() {
		const {stl, children, ...props} = this.props
		return (
			<Box stl={[style, stl ? stl : undefined]} innerRef={this.allowScrollRef} {...props}>
				{children}
			</Box>
		)
	}
}

Suggestions:

  1. Perhaps we can create a similar component, which is more generic and not dependent on Emotion, and export it as part of the library?
  2. The documentation should elaborate on how to use the library. My English is not native, but I can offer a PR.

carpben avatar Apr 12 '19 14:04 carpben

#104 fixed this for me

phelma avatar Apr 17 '19 15:04 phelma

I agree with @carpben that we should put more focus in README onto which node should be passed to disableBodyScroll(targetElement).

Specifically, that the element we would like to allow scroll on, is the same element we should pass to disableBodyScroll (and not a parent of that element) and on which we should apply the following css:

It would probably save my last 1-2h ;p

jtomaszewski avatar Apr 23 '19 13:04 jtomaszewski

Thank you @carpben I was trying for years to figure out the combination where everything would work as intended.

knitevision1 avatar May 05 '19 12:05 knitevision1

Readme updated to emphasise target element that you want to persist scrolling for is element you want to allow scroll ON, and not the parent of the element you want to allow scrolling for.

Thanks for the tip. 😃

willmcpo avatar May 09 '19 21:05 willmcpo

Aside from overflow-y: auto and -webkit-overflow-scrolling: touch, I had to add height: calc(100% + 1px) in order for scroll to work on iOS Safari when content is dynamically rendered. I think a component like this could be useful

// scroll-lock.tsx
import React, { useEffect, useRef } from "react";
import { disableBodyScroll, enableBodyScroll, clearAllBodyScrollLocks } from "body-scroll-lock";

export const ScrollLock: React.FC = ({ children }) => {
    const node = useRef<HTMLDivElement>(null);

    useEffect(() => {
        if (node && node.current) {
            disableBodyScroll(node.current, { reserveScrollBarGap: true });
        }

        return (() => {
            if (node && node.current) {
                enableBodyScroll(node.current);
            }
            clearAllBodyScrollLocks();
        });
    }, []);

    if (children) {
        return (
            <div ref={node} css={{
                overflowY: "auto",
                WebkitOverflowScrolling: "touch",
                height: "calc(100% + 1px)", // fixes an iOS Safari bug where dynamically rendered content beyond the viewport doesn't scroll
            }}>
                { children }
            </div>
        );
    }

    return <div ref={node} />
};

alxhghs avatar May 17 '19 20:05 alxhghs

-webkit-overflow-scrolling is non-standard, why are we using it

https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-overflow-scrolling

I am unable to scroll on iOS using any browser

recreated issue with this pen (using react-modal)

https://codesandbox.io/s/suspicious-smoke-ow4mu

jmayergit avatar Jul 16 '19 08:07 jmayergit

You don’t have to use WebKit-overflow-scrolling if you don’t want. It makes scroll smooth on iOS and is optional. It won’t do anything on other browsers but is widely used for iOS.

Overflow-y: auto and height: 100%+1px fixes two iOS scroll bugs.

I believe this library uses overflow: hidden. iOS doesn’t respect overflow hidden for scroll lock containers but overflow auto does work.

Height: 100% + 1px is a hack to allow scroll lock for dynamic content that goes beyond the height of the view port (again, iOS). This forces iOS to allow for vertical scroll of content that goes beyond the height of the view port.

@jmayergit if you try out this CSS (see my example above) you should be able to get it to work.

alxhghs avatar Jul 16 '19 10:07 alxhghs

@alxhghs great. setting overflowY: auto and height: calc(100% +- [number]px) allows for scrollable content on iOS modals

though it makes the modals look janky on desktop so I check for iOS platform and only use the above css for iOS.

I check for desktop or mobile and simply use overflow: hidden for desktops because the javascript of this package messes up my complex modal animations on Safari Browser for desktop.

jmayergit avatar Jul 18 '19 14:07 jmayergit

height: calc(100% +- [number]px) hack works but as I reach at the end of the scroll. Scrolling doesn't work again.

Tushar-Tilwani avatar Jul 31 '19 23:07 Tushar-Tilwani

They stopped the repairs. I had to do it myself, in the same way, with a new version of typeScript. And fix these problems for everyone to use.

npm i body-scroll-lock-upgrade

repair log,Refer to the releases page.

rick-liruixin avatar Apr 15 '23 07:04 rick-liruixin