Moving the mouse: mouseover/out, mouseenter/leave
Let’s dive into more details about events that happen when the mouse moves between elements.
Events mouseover/mouseout, relatedTarget
The mouseover event occurs when a mouse pointer comes over an element, and mouseout – when it leaves. These events are special, because they have property relatedTarget. This property complements target. When a mouse leaves one element for another, one of them becomes target, and the other one - relatedTarget. For mouseover: - event.target – is the element where the mouse came over. - event.relatedTarget – is the element from which the mouse came (relatedTarget -> target). For mouseout the reverse: - event.target – is the element that the mouse left. - event.relatedTarget – is the new under-the-pointer element, that mouse left for (target -> relatedTarget).
Skipping elements
The mousemove event triggers when the mouse moves. But that doesn’t mean that every pixel leads to an event. The browser checks the mouse position from time to time. And if it notices changes then triggers the events. That means that if the visitor is moving the mouse very fast then some DOM-elements may be skipped: If the mouse moves very fast from #FROM to #TO elements as painted above, then intermediate
Mouseout when leaving for a child
An important feature of mouseout – it triggers, when the pointer moves from an element to its descendant, e.g. from #parent to #child in this HTML: If we’re on #parent and then move the pointer deeper into #child, we get mouseout on #parent! That may seem strange, but can be easily explained. According to the browser logic, the mouse cursor may be only over a single element at any time – the most nested one and top by z-index. So if it goes to another element (even a descendant), then it leaves the previous one. Please note another important detail of event processing. The mouseover event on a descendant bubbles up. So, if #parent has mouseover handler, it triggers: As shown, when the pointer moves from #parent element to #child, two handlers trigger on the parent element: mouseout and mouseover: If we don’t examine event.target inside the handlers, then it may seem that the mouse pointer left #parent element, and then immediately came back over it. But that’s not the case! The pointer is still over the parent, it just moved deeper into the child element. If there are some actions upon leaving the parent element, e.g. an animation runs in parent.onmouseout, we usually don’t want it when the pointer just goes deeper into #parent. To avoid it, we can check relatedTarget in the handler and, if the mouse is still inside the element, then ignore such event. Alternatively we can use other events: mouseenter and mouseleave, that we’ll be covering now, as they don’t have such problems.
Events mouseenter and mouseleave
Events mouseenter/mouseleave are like mouseover/mouseout. They trigger when the mouse pointer enters/leaves the element. But there are two important differences: 1. Transitions inside the element, to/from descendants, are not counted. 2. Events mouseenter/mouseleave do not bubble. These events are extremely simple. When the pointer enters an element – mouseenter triggers. The exact location of the pointer inside the element or its descendants doesn’t matter. When the pointer leaves an element – mouseleave triggers.
Event delegation
Events mouseenter/leave are very simple and easy to use. But they do not bubble. So we can’t use event delegation with them. Imagine we want to handle mouse enter/leave for table cells. And there are hundreds of cells. The natural solution would be – to set the handler on
| , then only a handler on that | is able to catch it.
Handlers for mouseenter/leave on
|