Search code examples
javascriptjquerycsstouchscreenmouseleave

How to manually trigger the mouseleave event on a mobile device


I want to change a link color to orange on hover.

On a mobile device, when the user touches the link, it becomes orange and will remain orange until the user clicks away. So I want to manually trigger the mouseout event so that the link looses it's hover effect after 1 seconds.

This is what I have tried but the link remains orange after 1 second:

$(window).on('load', function() {
  $('a').on('click', function() {
    
    // on a mobile device, I want the hover effect to end after 1 seconds
    window.setTimeout(function() {
      $('a').trigger('mouseout');
    }, 1000);
  
  });
});
a {
  font-size: 2rem;
}

a:hover {
  color: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
  <a href='#'>Test</a>
</div>


Note: this is a simplified example, in my code I am not using a timer instead I want to trigger the mouseout event on ajaxcomplete

$(document).on('ajaxComplete', function () {
    $('a').trigger('mouseout');
});

Solution

  • The problem is trying to force a mouseout event doesn't seem to work on a touch device.

    The series of events that is fired on a touch device starts with a touchstart event - see e.g. MDN

    If the browser fires both touch and mouse events because of a single user input, the browser must fire a touchstart before any mouse events.

    This snippet remembers that the user has started a touch event and instead of acting on mouse events it sets a class which changes the text color. The same is done on mouse events, which are only acted on when the user is not appearing to be using a touch device on this element.

    While it would seem logical to look subsequently for the touchend event on the element, it seems that if the user does a long touch on it, given it is an anchor element, the touchend event is not fired on the element when they remove their finger/pointing device. It is however still fired on the window and so we catch that event and remove the hover class.

    let usingTouch = false;
    const a = document.querySelector('a');
    a.addEventListener('touchstart', function() {
      usingTouch = true;
      a.classList.add('hover');
    });
    window.addEventListener('touchend', function() {
      usingTouch = true;
      setTimeout(function() {
        a.classList.remove('hover');
      }, 1000);
    });
    a.addEventListener('mouseover', function() {
      if (!usingTouch) a.classList.add('hover');
    });
    a.addEventListener('mouseout', function() {
      if (!usingTouch) a.classList.remove('hover');
    });
    a {
      font-size: 2rem;
    }
    
    .hover {
      color: orange;
    }
    <div>
      <a href='#'>Test</a>
    </div>