Back to Home

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

elements (or some of them) may be skipped. The mouseout event may trigger on #FROM and then immediately mouseover on #TO. That’s good for performance, because there may be many intermediate elements. We don’t really want to process in and out of each one. On the other hand, we should keep in mind that the mouse pointer doesn’t “visit” all elements along the way. It can “jump”. In particular, it’s possible that the pointer jumps right inside the middle of the page from out of the window. In that case relatedTarget is null, because it came from “nowhere”:

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

and process events there. But mouseenter/leave don’t bubble. So if such event happens on
, then only a handler on that is able to catch it. Handlers for mouseenter/leave on only trigger when the pointer enters/leaves the table as a whole. It’s impossible to get any information about transitions inside it. So, let’s use mouseover/mouseout. Let’s start with simple handlers that highlight the element under mouse: In our case we’d like to handle transitions between table cells
: entering a cell and leaving it. Other transitions, such as inside the cell or outside of any cells, don’t interest us. Let’s filter them out. Here’s what we can do: - Remember the currently highlighted in a variable, let’s call it currentElem. - On mouseover – ignore the event if we’re still inside the current . - On mouseout – ignore if we didn’t leave the current . Here’s an example of code that accounts for all possible situations: [js src=“mouseenter-mouseleave-delegation-2/script.js”] Once again, the important features are: 1. It uses event delegation to handle entering/leaving of any inside the table. So it relies on mouseover/out instead of mouseenter/leave that don’t bubble and hence allow no delegation. 2. Extra events, such as moving between descendants of are filtered out, so that onEnter/Leave runs only if the pointer leaves or enters as a whole.

Summary

We covered events mouseover, mouseout, mousemove, mouseenter and mouseleave. These things are good to note: - A fast mouse move may skip intermediate elements. - Events mouseover/out and mouseenter/leave have an additional property: relatedTarget. That’s the element that we are coming from/to, complementary to target. Events mouseover/out trigger even when we go from the parent element to a child element. The browser assumes that the mouse can be only over one element at one time – the deepest one. Events mouseenter/leave are different in that aspect: they only trigger when the mouse comes in and out the element as a whole. Also they do not bubble.

In the example below each face and its features are separate elements. When you move the mouse, you can see mouse events in the text area.

Each event has the information about both `target` and `relatedTarget`:

[codetabs src="mouseoverout" height=280]
Example:

Follow the lesson from Microsoft Web-Dev-For-Beginners course

Tags: web,development

© US Tutorials. All rights reserved.