document.ontouchmove and scrolling on iOS 5
Asked Answered
H

5

47

iOS 5 has brought a number of nice things to JavaScript/Web Apps. One of them is improved scrolling. If you add

-webkit-overflow-scroll:touch;

to the style of a textarea element, scrolling will work nicely with one finger.

But there's a problem. To prevent the entire screen from scrolling, it is recommended that web apps add this line of code:

document.ontouchmove = function(e) {e.preventDefault()};

This, however, disables the new scrolling.

Does anyone have a nice way to allow the new scrolling within a textarea, but not allow the whole form to scroll?

Hephzibah answered 17/10, 2011 at 18:56 Comment(5)
You could try yourScrollElement.ontouchmove=function(e) {e.preventDefault()}; Not sure if it works.Camala
No - that does not work. Thanks!Hephzibah
Must be some confusion there, because Gerben's suggestion is the exact same as Brian Nickel's alternate suggestion below.Hectorhecuba
@ElliotNelson He used stopPropagation where I used preventDefault. Not sure why that work.Camala
A correction: the CSS style attribute name should be "-webkit-overflow-scrolling", not "-webkit-overflow-scroll".@HephzibahInestimable
W
56

Update Per Alvaro's comment, this solution may no longer work as of iOS 11.3.

You should be able to allow scrolling by selecting whether or not preventDefault is called. E.g.,

document.ontouchmove = function(e) {
    var target = e.currentTarget;
    while(target) {
        if(checkIfElementShouldScroll(target))
            return;
        target = target.parentNode;
    }

    e.preventDefault();
};

Alternatively, this may work by preventing the event from reaching the document level.

elementYouWantToScroll.ontouchmove = function(e) {
    e.stopPropagation();
};

Edit For anyone reading later, the alternate answer does work and is way easier.

Watchmaker answered 17/10, 2011 at 21:5 Comment(4)
Great an simple solution. Alternative jquery plugin solution hakoniemi.net/labs/nonbounceDagostino
I believe you should be using e.target, not e.currentTarget, as e.currentTarget will always refer to the element the listener is attached to, in this case document.Porcupine
@Alvaro have you found a solution?Aikoail
@Aikoail yes, use touchstart instead, see my question here: #49926860Wahhabi
M
23

The only issue with Brian Nickel's answer is that (as user1012566 mentioned) stopPropagation doesn't prevent bubbling when you hit your scrollable's boundaries. You can prevent this with the following:

elem.addEventListener('touchstart', function(event){
    this.allowUp = (this.scrollTop > 0);
    this.allowDown = (this.scrollTop < this.scrollHeight - this.clientHeight);
    this.prevTop = null; 
    this.prevBot = null;
    this.lastY = event.pageY;
});

elem.addEventListener('touchmove', function(event){
    var up = (event.pageY > this.lastY), 
        down = !up;

    this.lastY = event.pageY;

    if ((up && this.allowUp) || (down && this.allowDown)) 
        event.stopPropagation();
    else 
        event.preventDefault();
});
Megawatt answered 3/6, 2013 at 13:46 Comment(4)
I could not get this to work on IOS6 and it actually prevented scrolling on pc browsers. On IOS it would only prevent elastic scrolling if you had already scrolled past the boundaries once.Freese
This solution doesn't quite seem to work. When the scroll reaches its top or bottom limit, the element simply freezes at its current position so that I cannot scroll in either direction. I am using iOS 7.1.Porcupine
Yes, exactly what he said ^Freese
To fix, replace all occurrences of event.pageY with event.targetTouches[0].pageY.Semitics
H
16

For anyone trying to acheive this with PhoneGap, you can disable the elastic scrolling in the cordova.plist, set the value for UIWebViewBounce to NO. I hope that helps anyone spending ages on this (like i was).

Herbst answered 1/6, 2012 at 7:31 Comment(2)
Thank YOU, Andrew! I only had to spend half an age looking for this!Blastoderm
Additional options/documentation on this: tripleshotsoftware.blogspot.com/2012/09/…Salaam
I
7

ScrollFix seems to be perfect solution. I tested it and it works like a charm!

https://github.com/joelambert/ScrollFix

/**
 * ScrollFix v0.1
 * http://www.joelambert.co.uk
 *
 * Copyright 2011, Joe Lambert.
 * Free to use under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 */

var ScrollFix = function(elem) {
    // Variables to track inputs
    var startY, startTopScroll;

    elem = elem || document.querySelector(elem);

    // If there is no element, then do nothing  
    if(!elem)
        return;

    // Handle the start of interactions
    elem.addEventListener('touchstart', function(event){
        startY = event.touches[0].pageY;
        startTopScroll = elem.scrollTop;

        if(startTopScroll <= 0)
            elem.scrollTop = 1;

        if(startTopScroll + elem.offsetHeight >= elem.scrollHeight)
            elem.scrollTop = elem.scrollHeight - elem.offsetHeight - 1;
    }, false);
};
Irrefutable answered 13/4, 2012 at 5:47 Comment(0)
U
2

It was frustrating to discover a known problem with stopPropagation and native div scrolling. It does not seem to prevent the onTouchMove from bubbling up, so that when scrolling beyond the bounds of the div (upwards at the top or downwards at the bottom), the entire page will bounce.

More discussion here and here.

Unshaped answered 25/10, 2011 at 11:7 Comment(1)
FYI, You can prevent this with the solution listed below.Megawatt

© 2022 - 2024 — McMap. All rights reserved.