2

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');
});
Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137
  • 1
    Wouldn't it be easier if you simply add a class on click and just remove the class after the ajaxComplete is triggered? – Hanlet Escaño Sep 28 '21 at 23:37
  • 1
    For what it is worth, it seems like most solutions would involve some hack-ish workarounds for a hover state that doesn't really make much sense in the context of a cursor-less environment. Might it be better to just suppress hover states for small screens or touch interfaces if the hover visual treatment represents a problem? – Alexander Nied Sep 29 '21 at 00:10

2 Answers2

2

a {
  font-size: 2rem;
}

a:hover {
  color: myanimation 1s 1;
  -webkit-animation:myanimation 1s 1;
}

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

This is solvable via a CSS animation, see the snippet above.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • Thanks but this would break the desktop functionality as orange will disappear after one second... also the 1 second was for demonstration I wanted to trigger the event on `ajaxcomplete` – Hooman Bahreini Sep 29 '21 at 00:06
  • 1
    @HoomanBahreini you can add a class called `mobile` to `body` when it's mobile and change the rule to `.mobile a:hover`. – Lajos Arpad Sep 29 '21 at 00:07
  • @HoomanBahreini you can also apply media queries to differentiate between the hovers, have your previous hover effect for large screens and the suggested one for smaller screens. – Lajos Arpad Sep 29 '21 at 00:21
  • Unfortunately 'testing for mobile' won't work given small viewports can be on mouse-enabled devices too and touch devices can be large. You'd need to check whether the user was using touch or mouse - and that's not reliable, they could be using both. – A Haworth Sep 29 '21 at 06:33
  • @AHaworth if such worries are present, then one can read information from the user agent and use that in order to determine whether it's a touch screen or not. In our example the device is a mobile device as specified in the question, this is why I assumed a small screen, as it's hard to imagine a person carrying a large TV screen on the street and using it. Yet, if we broaden the problem-space to touchscreens, then user agent data comes to our aid. – Lajos Arpad Sep 29 '21 at 23:19
2

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>
A Haworth
  • 30,908
  • 4
  • 11
  • 14