I created a website with jQueryMobile for iOS and Android.
I don\'t want the document itself to scroll. Instead, just an area (a
I was looking for a solution that did not require calling out specific areas that should scroll. Piecing together a few resources, here is what worked for me:
// Detects if element has scroll bar
$.fn.hasScrollBar = function() {
return this.get(0).scrollHeight > this.outerHeight();
}
$(document).on("touchstart", function(e) {
var $scroller;
var $target = $(e.target);
// Get which element could have scroll bars
if($target.hasScrollBar()) {
$scroller = $target;
} else {
$scroller = $target
.parents()
.filter(function() {
return $(this).hasScrollBar();
})
.first()
;
}
// Prevent if nothing is scrollable
if(!$scroller.length) {
e.preventDefault();
} else {
var top = $scroller[0].scrollTop;
var totalScroll = $scroller[0].scrollHeight;
var currentScroll = top + $scroller[0].offsetHeight;
// If at container edge, add a pixel to prevent outer scrolling
if(top === 0) {
$scroller[0].scrollTop = 1;
} else if(currentScroll === totalScroll) {
$scroller[0].scrollTop = top - 1;
}
}
});
This code requires jQuery.
Sources:
Update
I needed a vanilla JavaScript version of this, so the following is a modified version. I implemented a margin-checker and something that explicitly allows input/textareas to be clickable (I was running into issues with this on the project I used it on...it may not be necessary for your project). Keep in mind this is ES6 code.
const preventScrolling = e => {
const shouldAllowEvent = element => {
// Must be an element that is not the document or body
if(!element || element === document || element === document.body) {
return false;
}
// Allow any input or textfield events
if(['INPUT', 'TEXTAREA'].indexOf(element.tagName) !== -1) {
return true;
}
// Get margin and outerHeight for final check
const styles = window.getComputedStyle(element);
const margin = parseFloat(styles['marginTop']) +
parseFloat(styles['marginBottom']);
const outerHeight = Math.ceil(element.offsetHeight + margin);
return (element.scrollHeight > outerHeight) && (margin >= 0);
};
let target = e.target;
// Get first element to allow event or stop
while(target !== null) {
if(shouldAllowEvent(target)) {
break;
}
target = target.parentNode;
}
// Prevent if no elements
if(!target) {
e.preventDefault();
} else {
const top = target.scrollTop;
const totalScroll = target.scrollHeight;
const currentScroll = top + target.offsetHeight;
// If at container edge, add a pixel to prevent outer scrolling
if(top === 0) {
target.scrollTop = 1;
} else if(currentScroll === totalScroll) {
target.scrollTop = top - 1;
}
}
};
document.addEventListener('touchstart', preventScrolling);
document.addEventListener('mousedown', preventScrolling);