I\'m not able to prevent the main body content from scrolling while a fixed position overlay is showing. Similar questions have been asked many times, but all of the techniq
Simply changing the overflow scrolling behavior on the body worked for me:
body {
-webkit-overflow-scrolling: touch;
}
I was also facing same issue on safari(for ios). I gave thought to above all solution. but i was not convinced with the hacks. then i get to know about property touch-action. adding touch-action: none to overlay solved the issue for me. for the problem above add touch-action:none to the span inside overlay.
#overlay span {
position: absolute;
display: block;
right: 10px;
top: 10px;
font-weight: bold;
font-size: 44px;
cursor: pointer;
touch-action: none;
}
Bohdan's solution above is great. However, it doesn't catch/block the momentum -- i.e. the case when user is not at the exact top of the page, but near the top of the page (say, scrollTop being 5px) and all of a sudden the user does a sudden massive pull down! Bohand's solution catches the touchmove events, but since -webkit-overflow-scrolling is momentum based, the momentum itself can cause extra scrolling, which in my case was hiding the header and was really annoying.
In fact, -webkit-overflow-scrolling: touch is a double-purpose property.
overflow:scrolling container elements on iOS devices. The solution I came up with for myself was adapted from Bohdan's solution, but instead of blocking touchmove events, I am changing the aforementioned CSS attribute.
Just pass the element that has overflow: scroll (and -webkit-overflow-scrolling: touch) to this function at the mount/render time.
The return value of this function should be called at the destroy/beforeDestroy time.
const disableOverscroll = function(el: HTMLElement) {
function _onScroll() {
const isOverscroll = (el.scrollTop < 0) || (el.scrollTop > el.scrollHeight - el.clientHeight);
el.style.webkitOverflowScrolling = (isOverscroll) ? "auto" : "touch";
//or we could have: el.style.overflow = (isOverscroll) ? "hidden" : "auto";
}
function _listen() {
el.addEventListener("scroll", _onScroll, true);
}
function _unlisten() {
el.removeEventListener("scroll", _onScroll);
}
_listen();
return _unlisten();
}
Or, if you don't care about unlistening (which is not advised), a shorter answer is:
el = document.getElementById("overlay");
el.addEventListener("scroll", function {
const isOverscroll = (el.scrollTop < 0) || (el.scrollTop > el.scrollHeight - el.clientHeight);
el.style.webkitOverflowScrolling = (isOverscroll) ? "auto" : "touch";
}, true);
please, add -webkit-overflow-scrolling: touch; to the #overlay element.
And add please this javascript code at the end of the body tag:
(function () {
var _overlay = document.getElementById('overlay');
var _clientY = null; // remember Y position on touch start
_overlay.addEventListener('touchstart', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
_clientY = event.targetTouches[0].clientY;
}
}, false);
_overlay.addEventListener('touchmove', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
disableRubberBand(event);
}
}, false);
function disableRubberBand(event) {
var clientY = event.targetTouches[0].clientY - _clientY;
if (_overlay.scrollTop === 0 && clientY > 0) {
// element is at the top of its scroll
event.preventDefault();
}
if (isOverlayTotallyScrolled() && clientY < 0) {
//element is at the top of its scroll
event.preventDefault();
}
}
function isOverlayTotallyScrolled() {
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
return _overlay.scrollHeight - _overlay.scrollTop <= _overlay.clientHeight;
}
}())
I hope it helps you.
Combined Bohdan Didukh's approach with my previous approach to create an easy to use npm package to disable/enable body scroll.
https://github.com/willmcpo/body-scroll-lock
For more details on how the solution works, read https://medium.com/jsdownunder/locking-body-scroll-for-all-devices-22def9615177
When your overlay is opened, you can add a class like prevent-scroll to body to prevent scrolling of elements behind your overlay:
body.prevent-scroll {
position: fixed;
overflow: hidden;
width: 100%;
height: 100%;
}
https://codepen.io/claudiojs/pen/ZKeLvq