Scott Hunter
Scott Hunter

Reputation: 49803

Disable scrolling when touch moving certain element

I have a page with a section to sketch a drawing in. But the touchmove events, at least the vertical ones, are also scrolling the page (which degrades the sketching experience) when using it on a mobile browser. Is there a way to either a) disable & re-enable the scrolling of the page (so I can turn it off when each line is started, but turn it back on after each is done), or b) disable the default handling of touchmove events (and presumably the scrolling) that go to the canvas the sketch is drawn in (I can't just disable them completely, as the sketching uses them)?

I've used jquery-mobile vmouse handlers for the sketch, if that makes a difference.

Update: On an iPhone, if I select the canvas to be sketched in, or just hold my finger for a bit before drawing, the page doesn't scroll, and not because of anything I coded in the page.

Upvotes: 136

Views: 191881

Answers (12)

Norman
Norman

Reputation: 1

It's enough (to disable swipes) only with this code line in .js file:

window.addEventListener("touchmove", function (e) {
    e.preventDefault();
}, { passive: false });

P.S. Tested only on Chrome.

Upvotes: 0

Tyler
Tyler

Reputation: 500

In my case, I have a button which, when clicked, opens a div scrollable on the y-axis. On mobile, scrolling the div scrolls the whole page, and the touch-action CSS property doesn't help.

What I did was "redirect" the document scrolling to the element when the start of the touch originates from the element.

let touch_active = false;
let previous_y;
let element_to_scroll = document.querySelector('#your-element');

function is_element_to_scroll_open() {
    // Your logic goes here.
    return true;
}

document.addEventListener('touchstart', function(e) {
    let open = is_element_to_scroll_open();
    let within_boundaries = e.composedPath().includes(element_to_scroll);

    if (open && within_boundaries) {
        touch_active = true;
        previous_y = e.touches[0].clientY;
    }
}, {passive: false});

document.addEventListener('touchmove', function(e) {
    if (touch_active) {
        e.preventDefault();
        let current_y = e.touches[0].clientY;
        let scroll_difference = current_y - previous_y;
        element_to_scroll.scrollTop = element_to_scroll.scrollTop - scroll_difference;
        previous_y = current_y;
    }
}, {passive: false});

document.addEventListener('touchend', function(e) {
    if (touch_active) {
        touch_active = false;
        previous_y = null;
    }
}, {passive: false});

Upvotes: 1

AGrush
AGrush

Reputation: 1167

the modern way (2022) of doing this is using pointer events as outlined here in the mozilla docs: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events

Pointer events build on touchstart and other touch events and actually stop scroll events by default along with other improvements.

Upvotes: -1

Waqar
Waqar

Reputation: 163

this worked for me on iphone

$(".owl-carousel").on('touchstart', function (e) { 
            e.preventDefault();      
   });

Upvotes: 0

Phuocdh90
Phuocdh90

Reputation: 51

To my surprise, the "preventDefault()" method is working for me on latest Google Chrome (version 85) on iOS 13.7. It also works on Safari on the same device and also working on my Android 8.0 tablet. I am currently implemented it for 2D view on my site here: https://papercraft-maker.com

Upvotes: 2

Turnerj
Turnerj

Reputation: 4278

Note: As pointed out in the comments by @nevf, this solution may no longer work (at least in Chrome) due to performance changes. The recommendation is to use touch-action which is also suggested by @JohnWeisz's answer.

Similar to the answer given by @Llepwryd, I used a combination of ontouchstart and ontouchmove to prevent scrolling when it is on a certain element.

Taken as-is from a project of mine:

window.blockMenuHeaderScroll = false;
$(window).on('touchstart', function(e)
{
    if ($(e.target).closest('#mobileMenuHeader').length == 1)
    {
        blockMenuHeaderScroll = true;
    }
});
$(window).on('touchend', function()
{
    blockMenuHeaderScroll = false;
});
$(window).on('touchmove', function(e)
{
    if (blockMenuHeaderScroll)
    {
        e.preventDefault();
    }
});

Essentially, what I am doing is listening on the touch start to see whether it begins on an element that is a child of another using jQuery .closest and allowing that to turn on/off the touch movement doing scrolling. The e.target refers to the element that the touch start begins with.

You want to prevent the default on the touch move event however you also need to clear your flag for this at the end of the touch event otherwise no touch scroll events will work.

This can be accomplished without jQuery however for my usage, I already had jQuery and didn't need to code something up to find whether the element has a particular parent.

Tested in Chrome on Android and an iPod Touch as of 2013-06-18

Upvotes: 51

micahblu
micahblu

Reputation: 5212

I found that ev.stopPropagation(); worked for me.

Upvotes: 1

John Weisz
John Weisz

Reputation: 31924

Set the touch-action CSS property to none, which works even with passive event listeners:

touch-action: none;

Applying this property to an element will not trigger the default (scroll) behavior when the event is originating from that element.

Upvotes: 251

soanvig
soanvig

Reputation: 87

The ultimate solution would be setting overflow: hidden; on document.documentElement like so:

/* element is an HTML element You want catch the touch */
element.addEventListener('touchstart', function(e) {
    document.documentElement.style.overflow = 'hidden';
});

document.addEventListener('touchend', function(e) {
    document.documentElement.style.overflow = 'auto';
});

By setting overflow: hidden on start of touch it makes everything exceeding window hidden thus removing availability to scroll anything (no content to scroll).

After touchend the lock can be freed by setting overflow to auto (the default value).

It is better to append this to <html> because <body> may be used to do some styling, plus it can make children behave unexpectedly.

EDIT: About touch-action: none; - Safari doesn't support it according to MDN.

Upvotes: 7

user1720624
user1720624

Reputation:

document.addEventListener('touchstart', function(e) {e.preventDefault()}, false);
document.addEventListener('touchmove', function(e) {e.preventDefault()}, false);

This should prevent scrolling, but it will also break other touch events unless you define a custom way to handle them.

Upvotes: 19

Mehdi
Mehdi

Reputation: 418

There is a little "hack" on CSS that also allows you to disable scrolling:

.lock-screen {
    height: 100%;
    overflow: hidden;
    width: 100%;
    position: fixed;
}

Adding that class to the body will prevent scrolling.

Upvotes: 33

Woody
Woody

Reputation: 8002

try overflow hidden on the thing you don't want to scroll while touch event is happening. e.g set overflow hidden on Start and set it back to auto on end.

Did you try it ? I'd be interested to know if this would work.

document.addEventListener('ontouchstart', function(e) {
    document.body.style.overflow = "hidden";
}, false);

document.addEventListener('ontouchmove', function(e) {
    document.body.style.overflow = "auto";
}, false);

Upvotes: 1

Related Questions