Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/rick-liruixin/body-scroll-lock-upgrade
Body scroll locking that just works with everything 😏
https://github.com/rick-liruixin/body-scroll-lock-upgrade
angular body-scroll-lock body-scroll-lock-upgrade chrome ios mobile reack safari scroll-lock vuejs
Last synced: 2 days ago
JSON representation
Body scroll locking that just works with everything 😏
- Host: GitHub
- URL: https://github.com/rick-liruixin/body-scroll-lock-upgrade
- Owner: rick-liruixin
- License: mit
- Created: 2023-04-04T07:00:45.000Z (over 1 year ago)
- Default Branch: develop
- Last Pushed: 2024-02-28T06:21:23.000Z (9 months ago)
- Last Synced: 2024-11-11T06:34:47.838Z (3 days ago)
- Topics: angular, body-scroll-lock, body-scroll-lock-upgrade, chrome, ios, mobile, reack, safari, scroll-lock, vuejs
- Language: TypeScript
- Homepage:
- Size: 158 KB
- Stars: 112
- Watchers: 4
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# body-scroll-lock-upgrade
body-scroll-lock upgrade version, repair body-scroll-lock v4.0.0-beta.0 bug。
They stopped maintenance. I had to work it out myself, using the same approach, with a new version of typeScript. And fix the original problem, available for everyone to use.
# Changelog
Refer to the [releases](https://github.com/rick-liruixin/body-scroll-lock-upgrade/releases) page.
`If you think it works for you, please give me a star ⭐️ to encourage me`
go to [github](https://github.com/rick-liruixin/body-scroll-lock-upgrade) ⭐️⭐️⭐️⭐️⭐️
# source document
## Why BSL?
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 / VueJS
- supports nested target elements (eg. a modal that appears on top of a flyout)
- can reserve scrollbar width
- `-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-upgrade
or
$ npm install body-scroll-lock-upgrade
You can also load via a `` tag (refer to the lib folder).
## Usage examples
##### Common JS
```javascript
// 1. Import the functions
const bodyScrollLock = require('body-scroll-lock-upgrade');
const disableBodyScroll = bodyScrollLock.disableBodyScroll;
const enableBodyScroll = bodyScrollLock.enableBodyScroll;// 2. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
const targetElement = document.querySelector('#someElementId');// 3. ...in some event handler after showing the target element...disable body scroll
disableBodyScroll(targetElement);// 4. ...in some event handler after hiding the target element...
enableBodyScroll(targetElement);
```##### React/ES6
```javascript
// 1. Import the functions
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks,
} from 'body-scroll-lock-upgrade';class SomeComponent extends React.Component {
targetElement = null;componentDidMount() {
// 2. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
this.targetElement = document.querySelector('#targetElementId');
}showTargetElement = () => {
// ... some logic to show target element// 3. Disable body scroll
disableBodyScroll(this.targetElement);
};hideTargetElement = () => {
// ... some logic to hide target element// 4. Re-enable body scroll
enableBodyScroll(this.targetElement);
};componentWillUnmount() {
// 5. Useful if we have called disableBodyScroll for multiple target elements,
// and we just want a kill-switch to undo all that.
// OR useful for if the `hideTargetElement()` function got circumvented eg. visitor
// clicks a link which takes him/her to a different page within the app.
clearAllBodyScrollLocks();
}render() {
returnsome JSX to go here;
}
}
```##### React/ES6 with Refs
```javascript
// 1. Import the functions
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks,
} from 'body-scroll-lock-upgrade';class SomeComponent extends React.Component {
// 2. Initialise your ref and targetElement here
targetRef = React.createRef();
targetElement = null;componentDidMount() {
// 3. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
this.targetElement = this.targetRef.current;
}showTargetElement = () => {
// ... some logic to show target element// 4. Disable body scroll
disableBodyScroll(this.targetElement);
};hideTargetElement = () => {
// ... some logic to hide target element// 5. Re-enable body scroll
enableBodyScroll(this.targetElement);
};componentWillUnmount() {
// 5. Useful if we have called disableBodyScroll for multiple target elements,
// and we just want a kill-switch to undo all that.
// OR useful for if the `hideTargetElement()` function got circumvented eg. visitor
// clicks a link which takes him/her to a different page within the app.
clearAllBodyScrollLocks();
}render() {
return (
// 6. Pass your ref with the reference to the targetElement to SomeOtherComponent
some JSX to go here
);
}
}// 7. SomeOtherComponent needs to be a Class component to receive the ref (unless Hooks - https://reactjs.org/docs/hooks-faq.html#can-i-make-a-ref-to-a-function-component - are used).
class SomeOtherComponent extends React.Component {
componentDidMount() {
// Your logic on mount goes here
}// 8. BSL will be applied to div below in SomeOtherComponent and persist scrolling for the container
render() {
returnsome JSX to go here;
}
}
```##### Angular
```javascript
import { Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';// 1. Import the functions
import {
disableBodyScroll,
enableBodyScroll,
clearAllBodyScrollLocks,
} from 'body-scroll-lock-upgrade';@Component({
selector: 'app-scroll-block',
templateUrl: './scroll-block.component.html',
styleUrls: ['./scroll-block.component.css'],
})
export class SomeComponent implements OnDestroy {
// 2. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
@ViewChild('scrollTarget') scrollTarget: ElementRef;showTargetElement() {
// ... some logic to show target element// 3. Disable body scroll
disableBodyScroll(this.scrollTarget.nativeElement);
}hideTargetElement() {
// ... some logic to hide target element// 4. Re-enable body scroll
enableBodyScroll(this.scrollTarget.nativeElement);
}ngOnDestroy() {
// 5. Useful if we have called disableBodyScroll for multiple target elements,
// and we just want a kill-switch to undo all that.
// OR useful for if the `hideTargetElement()` function got circumvented eg. visitor
// clicks a link which takes him/her to a different page within the app.
clearAllBodyScrollLocks();
}
}
```##### Vanilla JS
Then in the javascript:
```javascript
import {
clearAllBodyScrollLocks,
disableBodyScroll,
enableBodyScroll,
} from "https://cdn.jsdelivr.net/gh/rick-liruixin/[email protected]/lib/index.esm.js";// 1. Get a target element that you want to persist scrolling for (such as a modal/lightbox/flyout/nav).
// Specifically, the target element is the one we would like to allow scroll on (NOT a parent of that element).
// This is also the element to apply the CSS '-webkit-overflow-scrolling: touch;' if desired.
const targetElement = document.querySelector("#someElementId");// 2. ...in some event handler after showing the target element...disable body scroll
disableBodyScroll(targetElement);// 3. ...in some event handler after hiding the target element...
enableBodyScroll(targetElement);// 4. Useful if we have called disableBodyScroll for multiple target elements,
// and we just want a kill-switch to undo all that.
clearAllBodyScrollLocks();// UMD
const open = () => {
document.querySelector(".dialog").style.display = "block";
document.querySelector(".mask").style.display = "block";
const targetElement = document.querySelector(".dialog");
bodyScrollLockUpgrade.disableBodyScroll(targetElement);
};
const close = () => {
document.querySelector(".dialog").style.display = "none";
document.querySelector(".mask").style.display = "none";
const targetElement = document.querySelector(".dialog");
bodyScrollLockUpgrade.enableBodyScroll(targetElement);
};
document.getElementById("open").addEventListener("click", open);
document.getElementById("close").addEventListener("click", close);```
## Demo
Check out the demo, powered by Vercel.
- https://bodyscrolllock.vercel.app for a basic example
- https://bodyscrolllock-modal.vercel.app for an example with a modal.## Functions
| Function | Arguments | Return | Description |
| :------------------------ | :------------------------------------------------------------- | :----: | :----------------------------------------------------------- |
| `disableBodyScroll` | `targetElement: HTMLElement`
`options: BodyScrollOptions` | `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 |## Options
### reserveScrollBarGap
**optional, default:** false
If the overflow property of the body is set to hidden, the body widens by the width of the scrollbar. This produces an
unpleasant flickering effect, especially on websites with centered content. If the `reserveScrollBarGap` option is set,
this gap is filled by a `padding-right` on the body element. If `disableBodyScroll` is called for the last target element,
or `clearAllBodyScrollLocks` is called, the `padding-right` is automatically reset to the previous value.```js
import { disableBodyScroll } from 'body-scroll-lock-upgrade';
import type { BodyScrollOptions } from 'body-scroll-lock-upgrade';const options: BodyScrollOptions = {
reserveScrollBarGap: true,
};disableBodyScroll(targetElement, options);
```### allowTouchMove
**optional, default:** undefined
To disable scrolling on iOS, `disableBodyScroll` prevents `touchmove` events.
However, there are cases where you have called `disableBodyScroll` on an
element, but its children still require `touchmove` events to function.See below for 2 use cases:
##### Simple
```javascript
disableBodyScroll(container, {
allowTouchMove: (el) => el.tagName === 'TEXTAREA',
});
```##### More Complex
Javascript:
```javascript
disableBodyScroll(container, {
allowTouchMove: (el) => {
while (el && el !== document.body) {
if (el.getAttribute('body-scroll-lock-ignore') !== null) {
return true;
}el = el.parentElement;
}
},
});
```Html:
```html
...
```## 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