Thomas

Javascript Mouseover Shenanigans

Est. Reading Time: 4 minutes

I ran into an issue with the JS mouseover event while scripting some extra functionality onto our homepage last week. I would expect the issue to be more commonly reported or documented, however I found few hints or online resources that discussed the matter after doing some thorough searching.  The problem I faced was anytime I’d hover one of the child elements (the links) to the containing div, the mouseout event would trigger and fade out the box—and the links with it… And un-clickable links are no good.   So,  mouseover on child elements triggers a mouseout of the parent. The page requirement was to have a link that once hovered, faded in a box with links contained inside—and when you hovered off, the box would fade away.  Naturally, I anticipated that the child elements of the div would still be considered “moused over” the div, however this isn’t the case and requires further DOM manipulation.

The instant the mouse cursor entered the box illustrated above in red, the entire box would fade out. The code looked similar to the following condensed markup:

<html>
<head>
	<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
	<script>
		function showLinks(){ jQuery('#linklist').fadeIn(250); }
		function hideLinks(){ jQuery('#linklist').fadeOut(250); }
	</script>
</head>
<body>
	<a href="#" onmouseover="showLinks();">Hover Link</a>
	<div id="linklist" style="display:none;" onmouseout="hideLinks();">
		<a href="#">Link</a><br />
		<a href="#">Link</a><br />
		<a href="#">Link</a><br />
		<a href="#">Link</a>
	</div>
</body>
</html>

I did manage to find an article that discussed this, however, the provided solution was not cross-browser compliant—a concept we work pretty hard at Beacon to maintain. The article is available at QuirksMode.org. One consideration was to pick up the location of the box once the mouseover event was triggered (faded in) and then tracking the mouse coordinates in comparison to a region of pixels around the box, to fire the fade-out routine. Instead, I managed a way by conditionally allowing the mouseout event to fire. Here’s a solution:

<html>
<head>
	<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
	<script>
		var isOverLink = false; var isOverDiv = false;
		function showLinks(){ jQuery('#linklist').fadeIn(250); }
		function hideLinks(){ if(!isOverLink && !isOverDiv) jQuery('#linklist').fadeOut(250); }
	</script>
</head>
<body>
	<a href="#" onmouseover="showLinks();">Hover Link</a>
	<div id="linklist" style="display:none;" onmouseover="isOverDiv = true;" onmouseout="isOverDiv = false; setTimeout('hideLinks()',250);">
		<a href="#" onmouseover="isOverLink = true;" onmouseout="isOverLink = false;">Link</a><br />
		<a href="#" onmouseover="isOverLink = true;" onmouseout="isOverLink = false;">Link</a><br />
		<a href="#" onmouseover="isOverLink = true;" onmouseout="isOverLink = false;">Link</a><br />
		<a href="#" onmouseover="isOverLink = true;" onmouseout="isOverLink = false;">Link</a>
	</div>
</body>
</html>

So, what changed? When the page loads, two boolean variables are defaulted to false–One for tracking when the Div is moused over, and one for all the links. The boolean values are switched to their respective state when mousing on and off the links or the Div box. Since the onmouseout is triggered each time we mouse over those links, we’ve put a 250-millisecond delay in calling the hideLinks function (only on the containing div’s onmouseout attribute) so that the variables have time to swap and under the condition that the user is neither hovered over the link or the div–and the box persists with clickable links!