2

Please check this codepen with a) Firefox and b) Chrome. Proceed as follows:

  1. Move mouse on link
  2. Click link and do not move mouse cursor at all afterwards
  3. Wait until page has reloaded.

If you haven't moved the mouse cursor, it will still be above the link after the page has reloaded.

Firefox will apply the :hover styles now.

Chrome (Mac OS X) will display the element in it's non-hovered state (which is what I prefer in my scenario).

Anyone here who has an idea which browser does it right, and how to get one browser mimic the other's behaviour?

For my current scenario, I'd like to know how to avoid :hover being triggered directly after page reload. I'd be quite unhappy if I had to resort to Javascript for that.

For completeness' sake, here's the demo's code:

<a href="https://codepen.io/connexo/pen/pEJbqj" target="_top">This Codepen</a>
a {
  color: #333;
  background-color: #ddd;
  display: inline-block;
  line-height: 40px;
  padding: 20px;
  text-decoration: none;
  transition-duration: .4s;
  &:before {
    content: "non-hovered";
  }
  &:hover {
    background-color: #a00;
    color: white;
    &:before {
      content: "hovered state";
    }
  }
}

Edit: As one of my colleagues just told me, it seems that Chrome behaves in the described way only on OS X, but not on Windows. Can anybody elaborate on the whole issue?

connexo
  • 41,035
  • 12
  • 60
  • 87

1 Answers1

1

Which behaviour is correct?

Difficult to say which is the correct behaviour as the W3C spec does not go into particular detail about the mechanics of the :hover pseudo class:

The :hover pseudo-class applies while the user designates an element with a pointing device, but does not necessarily activate it. For example, a visual user agent could apply this pseudo-class when the cursor (mouse pointer) hovers over a box generated by the element.

The user action pseudo-classes :hover, :active, and :focus

Both actions seem reasonable given the circumstances.

How to avoid :hover being triggered directly after page reload.

In this particular case it appears that you want to disable the hover state until the user has moved the mouse, to achieve this you could do the following:

  • Add the CSS property pointer-events: none; to the link on page load. This will disable any mouse events on the link
  • Attach a move event to the body which gets activated once when the user moves the mouse (after which it gets unbound)
  • In the move event set pointer-events: auto; on the link to enable mouse events on it

$("a").css("pointer-events", "none");
$("body").one("mousemove", function() {
  $("a").css("pointer-events", "auto");
});
a {
  color: #333;
  background-color: #ddd;
  display: inline-block;
  line-height: 40px;
  padding: 20px;
  text-decoration: none;
  transition-duration: .4s;
}
a:before {
  content: "non-hovered";
}
a:hover {
  background-color: #a00;
  color: white;
}
a:hover:before {
  content: "hovered state";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#" target="_top"></a>

The example is best viewed in either Codepen or JS Fiddle given that a Stack Snippet is collapsed by default.

Hidden Hobbes
  • 12,696
  • 3
  • 30
  • 59
  • Thank you for your detailed answer. So I assume you also do not see a solution which would work without Javascript? – connexo Sep 07 '16 at 14:43
  • Nothing springs to mind @connexo, I feel if there were a solution it would hinge upon `pointer-events` but I can't think of a way to unset it without using JavaScript. – Hidden Hobbes Sep 07 '16 at 14:49
  • Now that I'm about to implement the suggested solution, doubts crawl into my mind. Wouldn't pointer-events stay disabled on touch-devices this way? And if so, would adding `touchmove` on top of `mousemove` to the list of triggering events be the right event to hook on for solving this problem? – connexo Sep 09 '16 at 12:47
  • 1
    Hmm, that is a good point and in truth not something I considered. [I've amended the snippet](https://jsfiddle.net/chnk8t95/3/) to output text when `mousemove` is called and it does get fired on mobile (at least in Chrome and the stock browser on my Samsung S5). I don't have an iPhone or iPad handy to test those so if they don't work `touchmove` sounds like a plausible method. Another option may be to add a check for touch event support and turn on/off the code accordingly. See http://stackoverflow.com/a/20293441/3400962 for more info and https://jsfiddle.net/chnk8t95/4/ for it in practice. – Hidden Hobbes Sep 09 '16 at 13:25