-
-
Notifications
You must be signed in to change notification settings - Fork 31.6k
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
[Modal] Disable background scrolling in iOS #5750
Comments
And with Popover - when it's open you can scroll screen behind to negative position on iOS - very annoying... Anybody did research or some related links? |
@oliviertassinari I'm being bitten by this bug, too. I can try to fix it, though at the moment I'm not even sure where to start. Do you have any idea what can be causing this? |
@oliviertassinari Same problem on |
As raised by someone on the bootstrap thread, that seems to be a Safari browser bug. We can't do much about it here. I'm closing the issue. It's unfortunate. |
i had the issue with the popover component, so I added a custom BackdropComponent that cancels the touchmove event import * as React from 'react';
import Backdrop, { BackdropProps } from 'material-ui/Modal/Backdrop';
/**
* Prevents scrolling of content behind the backdrop.
*/
export class BackDropIOSWorkaround extends React.PureComponent<BackdropProps> {
protected onTouchMove(event: React.TouchEvent<HTMLDivElement>): void {
event.preventDefault();
}
public render(): JSX.Element {
return (
<Backdrop {...this.props} onTouchMove={this.onTouchMove}/>
);
}
} <Popover
BackdropInvisible={false}
BackdropComponent={BackDropIOSWorkaround}
anchorEl={this.clickElement}
onRequestClose={this.unexpandChoices}
anchorOrigin={{vertical: 'top', horizontal: 'left'}}
transformOrigin={{vertical: 'top', horizontal: 'left'}}
>
<List disablePadding={true}>
{this.choices()}
</List>
</Popover> |
@daniel-rabe 's solution looks good but would be for Material UI v1, not previous versions |
@oliviertassinari I see that the This would save a lot of people time in having to manually add |
@jpmoyn No, you would reset the scroll position to the top of the page by doing so. Users will no longer be at the right scroll position once the dialog is closed. |
Would it be possible to implement the onTouchMove workaround by default? I'm not sure it's possible to specify a custom BackdropComponent everywhere it's needed. This bug affects Dialog, Select, SwipeableDrawer, etc. |
you can override the default-props of material-ui's BackDrop before creating your App: import BackDrop from 'material-ui/Modal/Backdrop';
BackDrop.defaultProps = {...BackDrop.defaultProps, onTouchMove: preventBackdropScroll};
export function preventBackdropScroll(event: React.TouchEvent<HTMLElement>): void {
let target: HTMLElement | null = (event.target as HTMLDivElement);
while (target != null && target !== document.body) {
const scrollHeight: number = target.scrollHeight;
const clientHeight: number = target.clientHeight;
if (scrollHeight > clientHeight) {
return;
}
target = target.parentElement;
}
event.preventDefault();
} |
@daniel-rabe Sneaky! I like it. Unfortunately it didn't fix the issue for me. |
@jacobweber Are you saying #5750 (comment) workaround doesn't work? If it comes with no side effect, we could add it to the core of the library. |
It didn't work for me (although I could see the function being invoked). Although maybe I'm doing something differently; I didn't get a chance to investigate this too deeply. I also noticed that using |
the workaround does not work for current iOS, i dont know since when version exactly |
this solution works for me atm import Fade from 'material-ui/transitions/Fade';
function fadeOnEnter(node: HTMLElement, isAppearing: boolean): void {
let clientY: number | null = null; // remember Y position on touch start
const touchStart: (event: Event) => void = (event: Event) => {
if ((event as TouchEvent).targetTouches.length === 1) {
clientY = (event as TouchEvent).targetTouches[0].clientY;
}
};
const touchMove: (event: Event) => void = (event: Event) => {
if ((event as TouchEvent).targetTouches.length === 1) {
disableRubberBand(event as TouchEvent);
}
};
const disableRubberBand: (event: TouchEvent) => void = (event: TouchEvent) => {
const tmpClientY: number = event.targetTouches[0].clientY - (clientY || 0);
if (node.scrollTop === 0 && tmpClientY > 0) {
// element is at the top of its scroll
event.preventDefault();
}
if (isOverlayTotallyScrolled() && tmpClientY < 0) {
// element is at the top of its scroll
event.preventDefault();
}
};
const isOverlayTotallyScrolled: () => boolean = () => {
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
return node.scrollHeight - node.scrollTop <= node.clientHeight;
};
node.addEventListener('touchstart', touchStart, false);
node.addEventListener('touchmove', touchMove, false);
}
Fade.defaultProps = {...Fade.defaultProps, onEnter: fadeOnEnter}; |
Hopefully this will be fixed soon. For our use-case we we were having issues with fullscreen dialogs so we just capture the |
How about setting In the meantime here is what Ive done:
|
This PR adds the workaround that fixes the Safari bug 🙏 |
I stand corrected. this fixes the problem but losses scroll position. im trying another work around. |
There one more fix which can help for the majority of cases - inert which is coming to a full support (only Firefox is one little behind) |
ive implemented this hook, and if you place this in your index.js it should fix the safari bug...the basic idea is to set overflow hidden on the HTML tag, and reset the scroll position back when the modal closes.
|
I propose that in ModalManage's handleContainer function, we can also set scroll container's touch action style to "none" when open, and restore it when close. Although this will only work on IOS version 13 and later, I think this is OK as a temporary workaround until the iOS safari bug is fixed. You can try it here on your iOS device. @oliviertassinari If you think this workaround is OK, I will create a pull request, thanks! |
The issue definitely should be fixed on MUI level or on Safari level, but as temporary solution you can use just styling. // Media for Safari only |
I was banging my head for this one, so I might share a solution that worked like a charm using Dialog Mui. Check out this npm package: https://www.npmjs.com/package/inobounce You can add it without a dependency also. Just call it in your index.js just after your .render: iNoBounce.disable() And when opening your Dialog do iNoBounce.enable() and onClose iNoBounce.disable(). Works like a charm with Mui on IoS! Make sure your body has -webkit-overflow-scrolling: touch; |
Fix to resolve this problem. Working on my production web page with dropdowns, popovers, dialogs...
|
Woah, CSS is saving the world once again. touch-action sounds exactly like the solution |
The above solution (CSS: #5750 (comment) or JS: #5750 (comment)) will work until we have any input field in modal. If we have input field in modal and it's focused then we see scrolling of background again :( |
Along with |
You can Simply use this lines of code in the Select Component. onOpen={() => (document.body.style.touchAction = 'none')} |
Unfortunately if you do that and use the MuiDrawer, you lose your initial scroll.. So I have an infinite scroll, when I scroll down quite a bit, open my drawer, to check my filters and close it again, I will start at the top of the page. Which is really annoying for the user |
Not only that. If you add position fixed on the body, all sorts of weird UI changes will happen since it will mess with any other styling on the page. Even if you apply this in full screen dialogs you will have time to see the changes once you close the modal. The biggest issue is when you have to use some input field inside the modal which makes this even harder to solve. I'm honestly a bit shocked that this doesn't seem to be a bigger issue and that it has not been resolved yet. I mean, this issue has been opened since 2016 and we're still trying to make some strange hack to maybe get it to work. Modals are pretty important in websites and web apps. It's no secret that Apple does not like any sort of site/web app that could compare with a native app in any way so i'm not really surprised they don't want to solve this, but I still feel like there should be a better solution. |
Tested dialogs in http://www.material-ui.com/#/components/dialog.
On desktop Chrome, background scrolling is disabled when dialogs are shown.
However, it is not disabled in iOS Safari or Chrome.
The text was updated successfully, but these errors were encountered: