I need to know when the mouse cursor leaves a div
. So I hook up the mouseout
event. However, if I move the mouse very quickly out of the div
, the mouseout
event doesn't fire. That's right: the mouse cursor was sitting still inside the div
, it's now outside the div
, and yet the mouseout
callback hasn't been called. (It works fine if I don't move the mouse quite so fast.)
This is true in the latest Google Chrome by the way – so not just an "old browsers" problem.
A workaround:
A question about this problem has been posed before. Apparently it's just a fact of life, and the only workaround I've found is to manually monitor mousemove
events, each time checking the cursor's x/y co-ordinates and seeing if they fall within the div
’s bounding box, so you have more chances to "notice" if the cursor is no longer inside it.
Compared to letting the browser do all this natively, performing calculations on every pixel move is a bit of a performance hit. It's also tedious to code.
On to my question...
Why can't the browser can't reliably capture the mouseout
event? If I can reliably tell when the mouse has left the div
using the above workaround, why can't the browser do it?
I understand (from the answer linked above) that JavaScript doesn't try to interpolate "frames". Say if you put a mousemove
handler on the document
, and quickly move the mouse 200 pixels to the right in a perfect horizontal line, you might not get 200 mousemove
events. A few will be missed. I don't have a problem with that.
But if some pixel movements are missed just as the mouse crosses the boundary of the div
, why does it follow that the mouseout
event should also be skipped? When the browser finally starts registering the mouse's position again (after a sudden fast movement), even if the mouse is now miles outside the box, the point is that it used to be in the box and no longer is. So why doesn't it then fire the mouseout event then?
I just don't get why this would be a hard problem for the browser vendors to solve. (But I trust there might be a good reason, which I'm too stupid to think of.)
I'm posting this question mainly out of curiosity, but I'm hoping the answer might give some insight that could help me work around the problem more efficiently. Also, any alternative workarounds (which are faster than the one presented above) would be welcome.
The mouseout event is fired at an Element when a pointing device (usually a mouse) is used to move the cursor so that it is no longer contained within the element or one of its children.
Definition and UsageThe onmouseout event occurs when the mouse pointer is moved out of an element, or out of one of its children. Tip: This event is often used together with the onmouseover event, which occurs when the pointer is moved onto an element, or onto one of its children.
The mouseleave event occurs when the mouse pointer leaves the selected element. The mouseleave() method triggers the mouseleave event, or attaches a function to run when a mouseleave event occurs. Note: Unlike the mouseout event, the mouseleave event only triggers when the mouse pointer leaves the selected elements.
The mouseenter event is fired at an Element when a pointing device (usually a mouse) is initially moved so that its hotspot is within the element at which the event was fired.
I know that you don't want a workaround, but you don't need to check mouse's x/y to know if you are in or out an element. You could simply check the element from which the mousemove event was fired. If you put a mousemove on document, the event will fire from one of its children, and you can compare that element with your element to know if it is one of its descendants.
Or you could go up the parentNode tree and stop if you find your element. Then you know you are inside the element and still in it, otherwise you reach the document and you are out.
Some browsers implement the mouseenter/mouseleave events that, I've noticed, are more accurate than mouseout. Prototype and jQuery have a workaround for browsers that don't implement these new events. Mouseleave does not fire from an element's children, whereas mouseout does.
You describe moving the mouse very quickly. When you stop, is the pointer still within the page? That is, is your mouse pointer still hovering over some part of the visible web page?
If it has gone outside, then it's not necessarily clear what the browser should do. The mouseout
event should have a relatedTarget
property that targets what the mouse pointer has gone into. If the mouse pointer is already outside of the page area, there would be no related target to point to.
Put another way, when the mouse leaves the page area, the browser stops tracking it and stops reporting its position. If you move your mouse fast enough, from the browser's perspective, the mouse simply disappeared. It's not until you bring the mouse back into the bounding box of the viewable page that the browser knows where it is, and then triggers all appropriate movement-based actions (like mouseout).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With