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

Potential iOS scroll bug #468

Open
O4epegb opened this issue Jan 8, 2021 · 12 comments
Open

Potential iOS scroll bug #468

O4epegb opened this issue Jan 8, 2021 · 12 comments
Labels

Comments

@O4epegb
Copy link

O4epegb commented Jan 8, 2021

Hi, everyone! First of all, thanks for nice library, great job!

Bug report

Describe the bug

I've encountered strange problem with scroll, not quite sure if this is because of some weird bug or maybe I am doing something wrong, or it just Safari css behaviour.

Anyway, so if you make full screen modal with css flexbox then it won't let you scroll content inside of it on iOS. It works fine on Desktop (Mac, Window), have not tested on Android.

I saw an issue about scroll and I waited for the fix, but it did not fixed it actually.
#462

And if you disable scroll block (blockScroll={false}) then it actually works, but not quite good because, well, body scroll is not disabled and it is wonky.

To Reproduce

Open modal on iOS, try to scroll

Expected behavior

You can scroll to the end

Screenshots

Codesandbox:
https://xop8k.csb.app/

System information

  • Version of react-responsive-modal: [e.g. 6.0.1]
  • Version of react: [e.g. 17.0.1]
@O4epegb O4epegb added the bug label Jan 8, 2021
@genox
Copy link

genox commented Mar 3, 2021

Similar issue. Trying to scroll on a video element which has a div element stretched over it (pos absolute), horizontally within a mobile viewport. The peculiar thing is that sometimes I can scroll as I would expect, but as soon as the movement/slow ease out of the scroll animation stops, scrolling is not possible anymore for a while. Then, when quickly trying to move the element, sometimes it "grabs" the element again and scrolls as desired.

The same approach works fine on desktop browsers, so I think it's an iOS webkit specific issue - or touch event related.

@pradel
Copy link
Owner

pradel commented Mar 4, 2021

As I don't have an IOS device I can't debug and fix this issue. If anyone wants to give it a try I would gladly accept a pr to fix this :)

@genox
Copy link

genox commented Mar 4, 2021

Thanks for your reply. I know this is a tricky one and honestly, I don't even know where to start looking for the root cause. And with these odds, for now I'll just stick to a workaround. What I was able to figure out is basically the same as OP: If the body scroll is locked on iOS Safari, scroll within the modal is (randomly, for some reason) locked, too.

From past experiences with issues on scroll locking, I know that iOS Safari is very anal about various techniques and - but don't pin me down on that - it might have something to do with touch event propagation, in which case we can't do anything, anyways. I ended up targeting iOS Safari with a dirty hack and set blockScroll={!isIosSafari()}. This basically solves the issue for me.

If you would like access to an iOS testing environment, I can share some time on BrowserStack with you. Let me know. But for now I'd file it under "things that define my hate love with iOS". ;-)

@pradel
Copy link
Owner

pradel commented Mar 4, 2021

To block the scroll we use the body-scroll-lock npm package and by just taking a look at the IOS issues I can see that IOS seems to be a constant source of pain :D https://github.com/willmcpo/body-scroll-lock/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc
So the bug might actually be on this lib, making it even harder to debug.

@genox
Copy link

genox commented Mar 4, 2021

Oh.. oh.. now all the compartmentalised and suppressed memories come back.. exactly. I was playing around with this lib a few years ago and ended up in the exact same rabbit hole. Oh well. Maybe just document the iOS issue potential and suggest browser or feature detection as a workaround then. Don't sink your time into this.

@pc035860
Copy link

I fork the example at https://2wyki.csb.app/ with height: 100% in styles.css commented out, and it works on my iOS 14.4.2 Safari.

It seems that body-scroll-lock requires setting disableBodyScroll on correct scroll container.
For the original example https://xop8k.csb.app/, actually, v6.0.0 will work, since it calls disableBodyScroll on modal rather than modal container.

Working version uses v6.0.0: https://qedbk.csb.app/ (only change the react-responsive-modal version)

  • v6.0.0: disableBodyScroll on modal
  • v6.0.1: disableBodyScroll on modal container

In conclusion, the scroll lock behavior highly depends on how you write your CSS, hence there are a lot of issues reported around body-scroll-lock package.

@bhj
Copy link

bhj commented Jun 25, 2021

A potential fix has been merged at willmcpo/body-scroll-lock#207; perhaps it's worth releasing a beta with it?

@Link2Twenty
Copy link

I've downgraded back to 5.1.1 for now as that doesn't seem to have to the issue.

@bhj
Copy link

bhj commented Dec 21, 2021

There is another PR at willmcpo/body-scroll-lock#229 that fixes some additional issues; just posting here for reference. Hopefully when that is merged and released it can be incorporated into this package.

@Feijo
Copy link

Feijo commented Jul 24, 2023

Any updates on this?

@Kepro
Copy link

Kepro commented Jul 24, 2023

Any updates on this?

willmcpo/body-scroll-lock#229 (comment)

@Feijo
Copy link

Feijo commented Jul 25, 2023

Given this lib is kinda dead, if you need a simple replacement, here it goes

import { css } from '@emotion/react';
import { MouseEvent, useEffect, useRef } from 'react';
import { GrClose } from 'react-icons/gr';

const styles = {
  root: css`
    width: 400px;
    border-radius: 8px;
    border: 1px solid #888;

    ::backdrop {
      background: rgba(0, 0, 0, 0.3);
    }
  `,
  close: css`
    position: absolute;
    right: 15px;
  `,
};

const isClickInsideRectangle = (e: MouseEvent, element: HTMLElement) => {
  const r = element.getBoundingClientRect();

  return e.clientX > r.left && e.clientX < r.right && e.clientY > r.top && e.clientY < r.bottom;
};

type Props = {
  title?: string;
  open: boolean;
  showCloseIcon?: boolean;
  onClose: () => void;
  children: React.ReactNode;
};

const Modal = ({ title, open, showCloseIcon, onClose, children }: Props) => {
  const ref = useRef<HTMLDialogElement>(null);

  useEffect(() => {
    if (open) {
      ref.current?.showModal();
      document.body.classList.add('modal-open'); // Add this to your main styles file: body.modal-open { overflow: hidden; }
    } else {
      ref.current?.close();
      document.body.classList.remove('modal-open');
    }
  }, [open]);

  return (
    <dialog
      ref={ref}
      css={styles.root}
      onCancel={onClose}
      onClick={(e) => ref.current && !isClickInsideRectangle(e, ref.current) && onClose()}
    >
      {showCloseIcon !== false && (
        <div css={styles.close} onClick={onClose}>
          <GrClose />
        </div>
      )}

      <h3>{title}</h3>

      {children}
    </dialog>
  );
};

export default Modal;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants