Conditionally block scrolling / touching events in mobile safari

iOS 5 now allows built-in overflow: scroll support.

I would like to disable the touchmove event for everyone except elements that have a scroll class or their children.

But I cannot make it work; this is what i worked with below:

 <html> <head> <style> .scrollable { height: 5em; overflow-y: scroll; -webkit-overflow-scrolling: touch; } </style> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <script> // doesn't seem to work var handleMove = function (e) { if (!$(e.target).parents().andSelf().hasClass('scrollable')) { e.preventDefault(); } }; document.addEventListener('touchmove', handleMove, true); </script> </head> <body> <div> don't scroll if you drag here </div> <div class='scrollable'> should be scrollable if you drag here <ul> <li>and here</li> <li>and here</li> <li>and here</li> <li>and here</li> <li>and here</li> <li>and here</li> <li>and here</li> <li>and here</li> </ul> </div> don't scroll if you drag here </body> </html> 
+7
javascript jquery mobile-safari cordova webkit
Dec 22 2018-11-22T00:
source share
6 answers

I know that some time has passed since you asked the question, but I had the same problem, and I used your code as the basis for solving the problem. So thanks for the inspiration.

(Javascript + jQuery)

 <script> var handleMove = function (e) { var scrollable = false; var items = $(e.target).parents(); $(items).each(function(i,o) { if($(o).hasClass("scrollable")) { scrollable = true; } }); if(!scrollable) e.preventDefault(); }; document.addEventListener('touchmove', handleMove, true); </script> 

Or a less detailed, but ultimately the same result (credit by J. Griffiths):

 <script> var handleMove = function (e) { if($(e.target).closest('.scrollable').length == 0) { e.preventDefault(); } } document.addEventListener('touchmove', handleMove, true); </script> 

You must also include the following META tag.

 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" /> 
+15
May 10 '12 at 17:39
source share

JavaScript version based on Nevirs answer:

 var initialY = null; var nodeStack = []; var $window = $(window); $window.bind('touchstart', function(e) { initialY = e.originalEvent.pageY; nodeStack = $(e.target).parents().andSelf().filter(':not(body, html)').get().reverse(); nodeStack = nodeStack.map(function(node) { return $(node); }); }); $window.bind('touchend touchcancel', function(e) { initialY = null; nodeStack = []; }); $window.bind('touchmove', function(e) { if (!initialY) { e.preventDefault(); } var direction = e.originalEvent.pageY - initialY; for (var i = 0; i < nodeStack.length; i +=1) { var $node = nodeStack[i]; var nodeHeight = $node.height(); var scrollHeight = $node[0].scrollHeight - 2; var nodeScrollTop = $node.scrollTop(); if (scrollHeight > nodeHeight) { // the user is dragging the content up, and the element is already scrolled down a bit. var allowedUp = direction > 0 && nodeScrollTop > 0; // the user is dragging the content down, and the element is up a bit. var allowedDown = direction < 0 && nodeScrollTop < scrollHeight - nodeHeight; if (allowedUp || allowedDown) { return; } } } // disable drag e.preventDefault(); }); 
+3
Feb 27 '13 at 15:36
source share

If you write this in the jquery document.ready event, this will work.

 $('body').on('touchmove', function (e) { if ($(e.target).closest("your_scrollable_div_selector").length == 0) e.preventDefault(); }); 
+2
Feb 20 '13 at 14:46
source share

I tried Scott answer, but it did not work on my iphone iOS 5.1.1

Also, this is especially important if you are creating a webClip application, damn it, I hope that iOS 6 will allow you to use the viewport tag, which disables automatic rollback

My version below works (or not), as well as Scott's answer above, since it essentially does the same.

jQuery 1.7.2

  $(document).bind("touchmove",function(e){ e.preventDefault(); }); $('.scrollable').bind("touchmove",function(e){ e.stopPropagation(); }); 
+1
05 Sep
source share

We can use the touchstart event instead of the touchmove event. One Finger Events says that no events are dispatched during panning, so touchmove may be too late.

I added the listener to the document, not to the body.

 document.ontouchstart = function(e){ e.preventDefault(); } 
0
Mar 07 '15 at 19:18
source share

Here (basically) a working solution for disabling vertical scrolling for all but overflowing elements:

(CoffeeScript):

 # Vertical scrolling behavior overrides. # # This disables vertical scrolling on the page for touch devices, unless the user is scrolling # within an overflowed node. This requires some finessing of the touch events. # # **NOTE:** This code ends up disabling bounce behavior if the user tries to scroll on a node that # is already at its upper or lower limit. window$ = $(window) initialY = null nodeStack = [] # When a user begins a (potential) drag, we jot down positional and node information. # # The assumption is that page content isn't going to move for the duration of the drag, and that # it would also be awkward if the drag were to change/stop part way through due to DOM # modifications. window$.bind 'touchstart', (evt) -> initialY = evt.originalEvent.pageY nodeStack = $(evt.target).parents().andSelf().filter(':not(body, html)').get().reverse() nodeStack = nodeStack.map (node) -> $(node) window$.bind 'touchend touchcancel', (evt) -> initialY = null nodeStack = [] # We override the `touchmove` event so that we only allow scrolls in allowable directions, # depending on where the user first began the drag. window$.bind 'touchmove', (evt) -> return evt.preventDefault() if initialY == null # A positive direction indicates that the user is dragging their finger down, thus wanting the # content to scroll up. direction = evt.originalEvent.pageY - initialY for node$ in nodeStack nodeHeight = node$.height() # For some reason, the node scrollHeight is off by 2 pixels in all cases. This may require # tweaking depending on your DOM. Concerning. scrollHeight = node$[0].scrollHeight - 2 nodeScrollTop = node$.scrollTop() # If we have a scrollable element, we want to only allow drags under certain circumstances: if scrollHeight > nodeHeight # * The user is dragging the content up, and the element is already scrolled down a bit. return if direction > 0 and nodeScrollTop > 0 # * And the reverse: the user is dragging the content down, and the element is up a bit. return if direction < 0 and nodeScrollTop < scrollHeight - nodeHeight # Otherwise, the default behavior is to disable dragging. evt.preventDefault() 
-one
Jan 10 2018-12-12T00:
source share



All Articles