jquery preventing hover function on touch

jquery touch events
jquery hover not working
simulate hover on touch devices
touch click event
jquery hover effects on div
jquery mouseenter
how to hover over links on mobile devices
javascript mobile click event

I have a hover function, if it's a touch device I'd like the hover event to NOT happen. The problem is when you tap the link with a touch device it does the hover event before doing the click event, so you have to tap it twice for it to work.

this is the hover function:

$("#close").hover( 
    function () { 
        $("#close_2").css({
            display: "none"
        });
        $("#close_1").css({
            display: "block"
        });
    }, 
    function () {
        $("#close_1").css({
            display: "none"
        });
        $("#close_2").css({
            display: "block"
        });;
    }
); 

and then I have this set up as the click function:

$('#close').click(function() {
    var id = $(this).attr('id');
    $('#full_image').animate({
        height: 0
    }, 300, function() {
        $('#full_image img').attr('src','#');
    });
    $("#close_1").css({
        display: "none"
    });
    $("#close_2").css({
        display: "none"
    });
    $("#close").css({
        display: "none"
    });
});

Make the .hover() method more explicit and combine it with .on():

var $close1 = $('#close_1'),
    $close2 = $('#close_2');

$('#close').on({
    mouseenter: function(){
        $close2.css({display:'none'});
        $close1.css({display:'block'});
    },
    mouseleave: function(){
        $close1.css({display:'none'});
        $close2.css({display:'block'});
    }
});

Then combine that with .off().

$('#close').on('touchstart',function(){
    $(this).off('mouseenter,mouseleave');
});

If you want the event to fire on click with touch devices, but on hover on desktop devices, then put the functions as a separate function you call within those actions respectively.

EDIT

Been a while since I did this answer, here is a better way:

$(function(){
    var isTouchDevice = ('ontouchstart' in window || 'onmsgesturechange' in window),
        $close = $('#close'),
        $close1 = $('#close_1'),
        $close2 = $('#close_2');

    if(!isTouchDevice){
        $close.on({
            mouseenter: function(){
                $close2.hide();
                $close1.show();
            },
            mouseleave: function(){
                $close1.hide();
                $close2.show();
            }
        });
    }

    $close.on('click',function(){
        $('#full_image').animate({height:0},300,function(){
            $(this).find('img').attr('src','#');
        });

        $close.hide();
        $close1.hide();
        $close2.hide();
    });
});

This doesn't require a "hover prevention" event to fire with each touch, basically sets capabilities on page load while not affecting the click event.

Mouseover (hover) on touch devices using jQuery, Do we sniff out touch devices and disable hover classes? Not at all: it can jQuery. To target just touch devices, I use the touchstart event on the links to bind to.*. To realize our goal, we need to accomplish the following using JavaScript (jQuery) User taps the ‘tappable hover’ link; Does the link have a hover class? If it does, allow the click to proceed (return true) If it does not, add the hover class, remove it from all other tappable hover links, and prevent the click from continuing (preventDefault)

I think a clear approach would be to:

  1. Detect if the browser supports touch events
  2. Add the hover event handler accordingly

If you're using something like Modernizr already:

if(!Modernizr.touch){
    // only if the browser doesn't support touch events,
    // add the hover handler here.
}
//add the click handler here, as you want it bound no matter what

See What's the best way to detect a 'touch screen' device using JavaScript? and What's the best way to detect a 'touch screen' device using JavaScript? for other options to detect touch capabilities.

.mouseleave(), An object containing data that will be passed to the event handler. handler. Type: Function( Event eventObject ). A function to execute each time the event is  The hover () method specifies two functions to run when the mouse pointer hovers over the selected elements. This method triggers both the mouseenter and mouseleave events. Note: If only one function is specified, it will be run for both the mouseenter and mouseleave events.

Because of Windows 8 and Ultrabooks, I expect to see a lot of devices that support both touch and pointer events. As a result, I avoid disabling the hover event outright since it could potentially break the site for an touch enabled user with a mouse.

To solve this problem I ended up using two different classes for displaying menus, .hover and .touch, as well as separate events for hover and tap.

I'm using jquery.finger for capturing tap events, though any plug-in should work, this was just the smallest one.

The HTML Would be something like:

<li>
    <a>Some Link</a>
    <div>Some Content</div>
</li>

The CSS would be something like:

li div {display:none;}
li.hover div, li.touch div {display:block;}

And the Javascript using JQuery:

// Caching whatever elements I'm using for the navigation
a = $("a");
li = $("li");

// Set hover events
li.hover(

    // Both hover in and out fire whenever the user taps, aggravating!
    function(e) {
        // Close unused menus
        li.not(this).removeClass("hover").removeClass("touch");

        // Show this menu
        $(this).addClass( "hover" );
    }, function(e) {
        // Only closes if the menu doesn't have .touch, hell yeah!
        li.removeClass("hover");
    }

);

// Set the tap event
a.on('tap',function(e,data){
    e.stopPropagation();
    var thisParent = $(this.parentNode);

    // Close unused menus
    li.not(thisParent).removeClass("touch");

    // Toggle the current menu
    thisParent.toggleClass("touch");

    // The menu is open, so we don't need this class anymore
    li.removeClass("hover");
});

// Prevent the list items when being tapped from closing the drop down
li.on('tap',function(e){e.stopPropagation();});

// Close drop downs when tapping outside the menus
$(document).on('tap',function(e){
   li.removeClass("touch");
});

The important take away here is how I'm adding a seperate .hover or .touch class depending on the event, as well as removing the unused classes. The order is important so the menus don't blink.

.one(), The handler is executed at most once per element per event type. above the alert could be displayed twice due to the two event types ( click and mouseover ). This is simple in jQuery $('.mensal').hover(function(e){ e.stopPropagation(); }); It occurs to me that this answer is completely unhelpful when dealing with CSS. Javascript events dont deal with CSS selectors or preventing them. Unfortunately, with CSS alone, I do not know of a way to accomplish this (and even in javascript it can get tricky).

On mobile side calling preventDefault in touchstart event prevents mouseover, mouseenter, mousedown and affiliated events. Detail: https://patrickhlauke.github.io/touch/tests/results/

    $('#close').on('touchstart',function(e){
        console.log('touchstart');
        e.preventDefault();
        //Do touch stuff
    });

Event Delegation, A handler can prevent the event from bubbling further up the document tree (and thus Deprecated in jQuery 1.8, removed in 1.9: The name "hover" used as a  Here they are using the non-standard touch-enabled media query feature, which I think is kinda weird and bad practice. But hey, in the real world I guess it works. In the future (when they are supported by all) those media query features could give you the same results: pointer and hover.

ended up using touch detection:

var deviceAgent = navigator.userAgent.toLowerCase();
var agentID = deviceAgent.match(/(iphone|ipod|ipad)/);

if(agentID) { 
    $('#close').click(function() {
        var id = $(this).attr('id');
        $('#full_image').animate({
            height: 0
        }, 300, function() {
            $('#full_image img').attr('src','#');
        });
        $("#close_1").css({
            display: "none"
        });
        $("#close_2").css({
            display: "none"
        });
        $("#close").css({
            display: "none"
        });
    });
}
else {
    $('#close').hover(
        function() {
            $("#close_2").css({
                display: "none"
            });
            $("#close_1").css({
                display: "block"
            });
        }, function() {
            $("#close_1").css({
                display: "none"
            });
            $("#close_2").css({
                display: "block"
            });
        }
    ); 
    $('#close').click(function() {
        var id = $(this).attr('id');
        $('#full_image').animate({
            height: 0
        }, 300, function() {
            $('#full_image img').attr('src','#');
        });
        $("#close_1").css({
            display: "none"
        });
        $("#close_2").css({
            display: "none"
        });
        $("#close").css({
            display: "none"
        });
    });
}

How to deal with :hover on touch screen devices, As you know, :hover behavior doesn't exist on touch screen devices. On iOS :​hover is triggered before the click event, so you will see the hover necessity to prevent default action for click event of the parent menu items Everything is enclosed in a regular jQuery(document).ready(function($){} function. Do not confuse the "hover" pseudo-event-name with the .hover() method, which accepts one or two functions. jQuery's event system requires that a DOM element allow attaching data via a property on the element, so that events can be tracked and delivered.

How to bind 'touchstart' and 'click' events but not respond to both , However, this also prevents other default browser behavior (like scrolling) – although usually you're handling the touch event entirely in your handler, and you  A function to execute when the mouse pointer enters or leaves the element. The .hover() method, when passed a single function, will execute that handler for both mouseenter and mouseleave events. This allows the user to use jQuery's various toggle methods within the handler or to respond differently within the handler depending on the event.type .

JQuery Mobile 1.4 How to Disable Hover Effect on Mobile Devices , First add this library: jquery.mobile.min.js JAVASCRIPT: // simulate hover effect on touch devices $('a.add_hover_effect').on('tap', function(e) { $(this). However, on touch devices I want it to expand and collapse on 'click', since hover events aren't very useful. To do that, I use :hover selector, and a backup .clicked class that is applied on touch events. The touchstart handler toggles the .clicked class and uses preventDefault to block the default action (which sets the :hover flag).

Handling Hover Events on a Touch Screen, $(function() { var touched = false, previous_touched; function updatePreviousTouched(e){ if(typeof previous_touched !== This maintains the speedy leveraging of CSS while avoiding dealing with the CSS And here is your working jQuery. You can use .bind() or .live() whichever is appropriate, but no need to name the function: $('#target').bind('click hover', function { // common operation }); or if you were doing this on lots of element (not much sense for an IE unless the element changes): $('#target').live('click hover', function { // common operation });

Comments
  • Try event.preventDefault() with hover. api.jquery.com/event.preventDefault
  • hmm how would you write that into it?
  • @Mihir That doesn't stop the method from executing, nor does it prevent the specified handlers from running. It prevents the default action, like the name suggests, which isn't the problem as described.
  • Ok, sorry I misunderstood. Can you not detect if the device is a touch device? If it is then don't call the function.
  • Specifying 'mouseenter' and 'mouseleave' specifically shouldn't make a difference, since hover is simply shorthand for that; the second method seems like it should work though. +1
  • hmm, so I added that little snipit in with the code I have posted above for hover and when I tap on the touch screen it still does the hover event first, then tap again and it does the click event.
  • @lifeinthegrey Here is where you can actually try spelling out the methods, the shorthand hover only works as a method now, the pseudoevent's use is deprecated so it doesn't work in 1.8+. $('#close').off('mouseenter mouseleave');. Just an idea.
  • ah damn i kind of suspected that but I had already changed it and didnt want to make it again haha ... code remodded
  • this will totally work, but adds completely unnecessary overhead of bringing in a library.
  • ... which is exactly why I said "If you're using something like Modernizr already" and included the links to SO questions discussing alternate methods of detection :)
  • This was exactly what I needed. Thanks.
  • This answer actually works (most answers here don't consider devices that have touchscreens + a mouse, like a touchscreen laptop), and is also the simplest answer.
  • It's not touch detection. Is detection "if user is fan of apple". Why this is accepted answer?