5

I have been using the following snippet to determine in Chrome/Safari & FF if a user is hovering over an anchor.

var isURL = $("a", obj).is(":hover");

I've seen varying posts about :hover being a CSS selector but what I can't get my head around is why the code returns true if there is 1 link within obj but throws a javascript unrecognized expression hover error if there are 2 or more.

Here is a fiddle of :hover working: - http://jsfiddle.net/2kyaJ/122/

Same but multiple elements (not working): - http://jsfiddle.net/2kyaJ/121/

Can anyone explain this to me?

By the way I have seen this... How do I check if the mouse is over an element in jQuery?

4 years on is this still the best and seemingly only way to determine if a user is hovering over an element? If yes would anyone be able to provide an example?

Edit: had to go fishing for exactly what I needed but it turns out this, as simple as it is works really well.

I am currently using it inside a plugin with jQuery 1.9.1 where I am triggering an animation on a mouseover of a parent element (obj). Hope someone else finds it useful in future. Use .length instead of .size as .size is deprecated from version 1.8 onwards.

        function isMouseOver() {
            if ($('a:hover', obj).length != 0) {
                return true;
            } else {
                return false;
            }                           
        }

Usage:

var isURL = isMouseOver();
Community
  • 1
  • 1
KryptoniteDove
  • 1,278
  • 2
  • 16
  • 31
  • Because for your logic to work, *all* `.sample` elements would have to be hovered at the same time. You need to check which element (if any) is hovered individually to achieve what you want here. – BenM Feb 26 '13 at 01:26
  • 1
    @BenM, if that's true, then [the documentation](http://api.jquery.com/is/) is wrong: "Check the current matched set of elements against a selector, element, or jQuery object and return `true` if **at least one** of these elements matches the given arguments." – redbmk Feb 26 '13 at 01:32
  • Well, check your console. Sizzle doesn't support `hover` for jQuery objects containing more than one element: `Uncaught Error: Syntax error, unrecognized expression: hover`. – BenM Feb 26 '13 at 01:34
  • If you upgrade to jQuery 1.9.1, the error message improves. `Syntax error, unrecognized expression: unsupported pseudo: hover`. This makes it clear that this is a limitation in jQuery's selectors. – Barmar Feb 26 '13 at 01:37

4 Answers4

5

:hover is not documented at http://api.jquery.com/ -- as such I wouldn't trust it to work in any particular way. The problem seems to be that Sizzle is getting confused by this pseudo-selector when there is more than one element to iterate over in the collection, although I can't really tell whey by looking at the code.

The fact that it is even working in your first example seems to be a bug: http://jsfiddle.net/2kyaJ/122/ -- it does not work with jQuery 1.9

As for how to tell if an element is hovered -- I'm not sure what circumstances you would need to do that. Instead, it's better to take action when a hover is triggered. You can bind to a "hover-like" event with mouseover and mouseenter. There is, of course, the CSS pseudo-selector :hover.

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • I am writing a plugin that when you hover over an element it slides to the left to reveal what is hidden on the right, on mouseout it slides back to the original position, if the user is hovering over a link I don't want to trigger the animation but I am already using setTimeout to wait 250 ms on mouseover and 1.5s on mouseout. – KryptoniteDove Feb 26 '13 at 01:50
3

Try this fiddle http://jsfiddle.net/2rU4U/:

setInterval(function(){
    var $sample = $(".sample");

    $sample.each(function(index) {
        if($(this).is(":hover")) {
           $(this).css("background", "yellow");
        }
        else {
           $(this).css("background", "");
        }
    });  
}, 200);

As mentioned in the comment above, this respects the fact that a collection of elements might be returned, not just a single one. Might cause quite a bit of overhead with lots of elements of course...!

J Griffiths
  • 701
  • 6
  • 14
  • Thanks, I was using the fiddle as an illustration of the behaviour really. It seems that part one of the question has been answered 'unsupported pseudo' but does anyone know the best way to determine if I am hovering over an element? or is the above with mouseover to fadeout still the way to go? – KryptoniteDove Feb 26 '13 at 01:41
1

As to why it doesn't work your way, I'd say it could be a bug or it could be that it's undocumented. I don't really know.

However, here's an example that works in jQuery 1.7.1, 1.9, and 2.0.0b1: http://jsfiddle.net/2kyaJ/125/

Basically instead of using .is() you can query for all hovered elements and then check that there is at least one match ($(".sample:hover").length rather than $(".sample").is(":hover")).

I got the impression you wanted to highlight all the .sample elements when any of them are hovered, hence the first jsfiddle. However, if you only want to highlight the hovered element, you could try something like this: http://jsfiddle.net/2kyaJ/126/

Also, if you're simply looking to bind something to the hover event, rather than checking more or less every 0.2 seconds you could just use the .hover() function: http://jsfiddle.net/2kyaJ/127/

redbmk
  • 4,687
  • 3
  • 25
  • 49
-2

Honestly, setting an interval is a terrible idea...

Just set a hover listener.

$('.sample').hover(function() {
    console.log($this) // $(this) is the currently hovered element
})

JSFiddle: http://jsfiddle.net/jeffshaver/2kyaJ/124/

Jeff Shaver
  • 3,315
  • 18
  • 19
  • This doesn't answer the question it changes all elements with the class of .sample to yellow. I want to determine what element is being hovered over. The fiddle is just an example of behaviour. – KryptoniteDove Feb 26 '13 at 13:04
  • Well, if you are trying to figure out which ".sample" is being hovered, then just do something with $(this) inside the hover listener... It still works... i.e. $('.sample').hover(function() { console.log($(this)); }); returns the html element that was hovered – Jeff Shaver Feb 26 '13 at 13:35