Alex Rivera | Logout

document.ontouchmove and scrolling on iOS 5

Asked 2011-10-17T18:56:43.567
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?

Edit
Report

3 Answers

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.

answered 2011-10-17T21:05:43.583
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();
});
answered 2013-06-03T13:46:00.897
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);
};
answered 2012-04-13T05:47:58.137

Your Answer