10

I wonder if its possible to prevent double-tap-to-zoom and double-tap-to-center on a specific HTML element in Safari iOS (iPad 1) ?

Because my small HTML5 game forces users to make fast clicks (or taps), which are interpreted as double clicks, and when it happens - the page changes zoom and centers itself.

Detecting double clicks (like in this answer - Safari iPad : prevent zoom on double-tap) smells bad..

Wrong answer #1: <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> - does not suit my purposes, because it will block any zoom.

Wrong answer #2: maybe would .preventDefault() on click event alone be enough for that ? - Does not have any effect.

Community
  • 1
  • 1
c69
  • 19,951
  • 7
  • 52
  • 82
  • [`-ms-touch-action: manipulation;`](http://blogs.msdn.com/b/ie/archive/2012/04/20/guidelines-for-building-touch-friendly-sites.aspx) sounds exactly like what i need. But its only supported by IE10. – c69 Apr 20 '12 at 23:57

8 Answers8

9

There's no other way than catching the events you want to prevent, and call preventDefault() on them, as you had already more or less figured out.

Indeed, some particular CSS properties / values may change the global site behavior (fixed width or fixed, for example), but you're not safe from changes to the OS (see fixedhandling change in iOS5), nor do these changes necessarily prevent all behavior (pinch might be off, but not double-tapping).

So, the best way to disable default behavior only for double-tapping is to take advantage of the count of touches iOS provides: if we have only one contact, then we're tapping. Two, this means we're pinching.

The following setup code provides that functionality:

var elm = document.body; // or some selection of the element you want to disable

var catcher = function(evt) {
    if (evt.touches.length < 2)
        evt.preventDefault();
};

elm.addEventListener('touchstart', catcher, true);

Demo on jsFiddle.

Note: the third parameter (true) to addEventListener means that we want to capture events, that is catch them all, even for our descendant children.

MattiSG
  • 3,796
  • 1
  • 21
  • 32
  • it would be bad, but acceptable, if `preventDefault()` worked.. but it does not. At least for `click` ... I'll try the same and also `stopPropagation()` for touch events, as well. ( the big obstacle is that 'my' iPad and my workplace are quite far from each other ). – c69 Nov 21 '11 at 00:31
  • What's the matter with `click`? You said you wanted to prevent double-tap to zoom. From my testing on an iOS device (iPhone 3GS), the fiddle shows the above code prevents zooming on double-tap. I don't understand why you're mentioning the `click` event :-S – MattiSG Nov 21 '11 at 07:19
  • i takes me on average 2-3 days between writing code and testing it on iPad, sorry. I hope to test it tomorrow. – c69 Nov 21 '11 at 10:07
  • ... ugh. Your example disables one-finger-double-tap zoom (cool!), but it also disables one-finger-tap completely (not so cool), so it even stops generating clicks. Two-finger-double-tap works, two-finger-pan works. Two-finger-pinch-zoom has some issues.. get a +1, though. – c69 Nov 22 '11 at 11:37
  • putting a `preventDefault()` listener on `touchend` seems to work much better. Yet somehow dumb iPad started to lag. Need to investigate that. – c69 Nov 22 '11 at 12:42
  • 2
    @c69 oh, thanks for the bounty! Did you award it because it ended or did it precisely solve your problem? We need to log the actual working answer [for the future](http://xkcd.com/979/) :) – MattiSG Nov 24 '11 at 13:31
7

I am preventing doubletaps like this:

var doubleTouchStartTimestamp = 0;
$(document).bind("touchstart", function (event) {
    var now = +(new Date());
    if (doubleTouchStartTimestamp + 500 > now) {
        event.preventDefault();
    }
    doubleTouchStartTimestamp = now;
});

The elegance lies within the fact, that no timeouts are needed. I only update a timestamp. It only gets compared on the next touchstart. Works for me on iOS 6.

Doubletaps further down the dom are not affected.

The same works without jQuery, as well:

var doubleTouchStartTimestamp = 0;
document.addEventListener("touchstart", function (event) {
    var now = +(new Date());
    if (doubleTouchStartTimestamp + 500 > now) {
        event.preventDefault();
    }
    doubleTouchStartTimestamp = now;
});
amenthes
  • 3,117
  • 1
  • 32
  • 38
6

I wrote a jQuery plugin for the same purpose - selectively disabling double-tap zoom on given page elements (in my case, navigation buttons to flip pages) I want to respond to every tap (including double-tap) as a normal click event, with no iOS "touch magic", no matter how fast the user clicks it.

To use it, just run something like $('.prev,.next').nodoubletapzoom(); on the elements you care for. The principle it uses is to listen for consecutive touchstart events on a node within 500ms, and running event.preventDefault() on the second, unless other touches are active at the same time. As that preventDefault consumes both touches, we also synthesize the two "missed" click events for the node, so your intended touch action happens as many times as the user intended.

ecmanaut
  • 5,030
  • 2
  • 44
  • 66
  • looks interesting. will try to test it, and respond with my conclusion. – c69 Mar 16 '12 at 06:44
  • This is a cool solution. I'm not able to get onclick="..." events to fire on the target items though when a double tap occurs. Do you have any ideas there? – Charlie Schliesser May 17 '12 at 16:25
  • Works for me: http://jsfiddle.net/ecmanaut/xptak/show/ - source code at http://jsfiddle.net/ecmanaut/xptak/ - maybe your page has handlers stealing those `click` (or `touchstart`) events and running `e.preventDefault()` or `e.stopPropagation()` on them before they get to your `onclick` handler. – ecmanaut May 19 '12 at 20:12
  • It works. Do you know if it is also possible to disable zoom on pinch? – viebel Jul 30 '12 at 14:51
0

JQuery approach to disable Double Tap Zoom in MVC4 To Disable the double tap (double mouse down) functionality on iOS 1+ you need to catch the touchStart Event and create an override to prevent the zoom.

// Using Single script.js and JQuery.Mobile-1.2.0 UI each page in MVC gets assigned JQuery through delegates so you don't have to do a full refresh of the page allowing you to take advantage of the data-prefetch which loads the page in the DOM when the app loads for the first time

$(document).delegate("#CashRegister", "pageinit", function () {

// To Disable 'Pinch to Zoom' Note: don't implement gester event handlers if you want to 
//keep pinch to zoom functionality NOTE: i use this as my pageinit is a delegate of a page
this.addEventListener("gesturestart", gestureStart, false);
this.addEventListener("gesturechange", gestureChange, false);
this.addEventListener("gestureend", gestureEnd, false);
//handle each event by disabling the defaults
function gestureStart(event) {
    event.preventDefault();
}

function gestureChange(event) {
    event.preventDefault();
}

function gestureEnd(event) {
    event.preventDefault();
}
//Recreate Double Tap and preventDefault on it
$(this).bind('touchstart', function preventZoom(e) {
// recreate the double tab functionality
        var t2 = e.timeStamp
      , t1 = $(this).data('lastTouch') || t2
      , dt = t2 - t1
      , fingers = e.originalEvent.touches.length; 
        $(this).data('lastTouch', t2);
        if (!dt || dt > 500 || fingers > 1) return; // not double-tap 
        e.preventDefault(); // double tap - prevent the zoom
        // also synthesize click events we just swallowed up
        $(this).trigger('click').trigger('click');
    });
Paul Styles
  • 150
  • 1
  • 5
0

Apple has a lot of tips with specialized tags for webkit (Safari). View Official Docs

master_gracey
  • 344
  • 1
  • 8
  • 18
  • I guess i'll just need to try my initial idea - [prevent default behaviour](http://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html#//apple_ref/doc/uid/TP40006511-SW24) – c69 Nov 10 '11 at 09:22
  • It is possible... I just can't find the code I used to do it unfortunately! Go to a site like foxnews.mobi; you can't pinch-zoom or double-tap-zoom. It is done with a special CSS webkit element. If I ever find the code I'll share it lol – master_gracey Nov 10 '11 at 14:58
  • Sorry, guys, it does not prevent anything. And at foxnews.mobi - there is width: 95%, thats why no zoom, but it centers content when you double-tap, so it not a good example. – c69 Nov 18 '11 at 10:54
0

What iOS version/Safari browser are you using? That site most definitely does not let you double-tap. I found some CSS but haven't had time to try it as I'm about to step out:

body {
  -webkit-text-size-adjust:none;
  margin:0px;
}

div{
  clear:both!important;
  display:block!important;
  width:100%!important;
  float:none!important;
  margin:0!important;
  padding:0!important;
}
master_gracey
  • 344
  • 1
  • 8
  • 18
0

You will need to implement a double tap function and preventDefault on the second tap. Here is some tested code that uses global variables that should get you started:

<button id="test1">Double Tap Me!</button>
<div id="test2">EMPTY</div>

var elm1 = document.getElementById('test1');
var elm2 = document.getElementById('test2');
var timeout;
var lastTap = 0;
elm1.addEventListener('touchend', function(event) {
    var currentTime = new Date().getTime();
    var tapLength = currentTime - lastTap;
    clearTimeout(timeout);
    if (tapLength < 500 && tapLength > 0) {
        elm2.innerHTML = 'Double Tap';
        event.preventDefault();
    } else {
        elm2.innerHTML = 'Single Tap';
        timeout = setTimeout(function() {
            elm2.innerHTML = 'Single Tap (timeout)';
            clearTimeout(timeout);
        }, 500);
    }
    lastTap = currentTime;
});

And a fiddle: http://jsfiddle.net/brettwp/J4djY/

Brett Pontarelli
  • 1,718
  • 15
  • 29
  • Thanks, but it isn't disabling zoom on my Android. Any ideas for that? – Gaurav Jan 20 '12 at 17:04
  • @Gaurav you might want to open a separate question for Android and include the specifics of what you are trying to accomplish and your target devices (phones, tablets, versions, etc.). – Brett Pontarelli Jan 20 '12 at 19:36
-1

Actually, .preventDefault() definitely does work... using jQuery:

var InputHandler = {    
    startEventType : isTouch ? "touchstart" : "mousedown"
}

$(selector).bind(InputHandler.startEventType, function(evnt) {
    evnt.preventDefault();
});

Your problem with trying to prevent on .click() is that the browser isn't throwing a "click" element. Safari only fires a click to help simulate a click... But when there's a double tab, Safair doesn't through a "click" element. Your event handler for .click() doesn't ever fire, and therefore the .preventDefault() doesn't fire either.

weisjohn
  • 793
  • 5
  • 9
  • 1
    this approach seems to detect touch clients. Actually, there's devices out there that are both touch and mouse, so this either/or distinction does not apply or will break a site for some users. – amenthes Nov 18 '15 at 20:25