Why body-scroll-lock ?
Enables body scroll locking (for iOS Mobile and Tablet, Android, desktop Safari/Chrome/Firefox) without breaking scrolling of a target element (eg. modal/lightbox/flyouts/nav-menus).
Features:
- disables body scroll WITHOUT disabling scroll of a target element
- works on iOS mobile/tablet
- works on Android
- works on Safari desktop
- works on Chrome/Firefox
- works with vanilla JS and frameworks such as React / Angular
- supports nested target elements (eg. a modal that appears on top of a flyout)
-webkit-overflow-scrolling: touch
still works
Aren't the alternative approaches sufficient?
- the approach
document.body.ontouchmove = (e) => { e.preventDefault; return false; };
locks the
body scroll, but ALSO locks the scroll of a target element (eg. modal). - the approach
overflow: hidden
on the body or html elements doesn't work for all browsers - the
position: fixed
approach causes the body scroll to reset - some approaches break inertia/momentum/rubber-band scrolling on iOS
Install
$ yarn add body-scroll-lock
or
$ npm install body-scroll-lock
Usage examples
Vanilla JS
const bodyScrollLock = require('body-scroll-lock');
const disableBodyScroll = bodyScrollLock.disableBodyScroll;
const enableBodyScroll = bodyScrollLock.enableBodyScroll;
const targetElement = document.querySelector("#someElementId");
disableBodyScroll(targetElement);
enableBodyScroll(targetElement);
React/ES6
import { disableBodyScroll, enableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock';
class SomeComponent extends React.Component {
targetElement = null;
componentDidMount() {
this.targetElement = document.querySelector('#targetElementId');
}
showTargetElement = () => {
disableBodyScroll(this.targetElement);
};
hideTargetElement = () => {
enableBodyScroll(this.targetElement);
}
componentWillUnmount() {
clearAllBodyScrollLocks();
}
render() {
return (
<div>
some JSX to go here
</div>
);
}
}
Demo
http://wp-os.s3-website-ap-southeast-2.amazonaws.com/body-scroll-lock-demo/index.html
Caveat
On iOS mobile (as is visible in the above demo), if you scroll the body directly even when the scrolling is
locked (on iOS), the body scrolls - this is not what this package solves. It solves the typical case where a modal
overlays the screen, and scrolling within the modal never causes the body to scroll too (when the top or bottom
within the modal has been reached).
Functions
Function | Argument | Return | Description |
---|
disableBodyScroll | targetElement: HTMLElement | void | Disables body scroll while enabling scroll on target element |
enableBodyScroll | targetElement: HTMLElement | void | Enables body scroll and removing listeners on target element |
clearAllBodyScrollLocks | null | void | Clears all scroll locks |
References
https://medium.com/jsdownunder/locking-body-scroll-for-all-devices-22def9615177
https://stackoverflow.com/questions/41594997/ios-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-posi