How to add a delayed hover effect with JavaScript
The Challenge
A client's website had a page with a gallery of partner logos; visitors could click each logo to trigger a modal showing details about the partnership.
They asked us to change the interaction so that visitors could hover over logos to see the modal, instead of having to click them. Seemed easy enough - but given the design, we had issues where closing the modal immediately re-opened it for the partner underneath the "close" button, resulting in a loop that was hard to break.
Our Star Trek-ified example of what was happening:
The Solution
Here's our first stab, which resulted in the loop from above:
initListeners: => $(".js-character-image").on "mouseover", @onCharacterHover $(".js-close-details").on "click", @onCloseDetailsClick onCharacterHover: (ev) => $(".js-character-details").hide()
$character = $(ev.target).closest(".js-character-image") position = $character.position().top $details = $character.next(".js-character-details") $details.css("top", position) $details.slideDown() onCloseDetailsClick: (ev) -> $descriptionContainer = $(ev.target).closest(".js-character-details") $descriptionContainer.slideUp()
To fix the instantaneous loop issue, we added a timeout
, so that the code wouldn't immediately execute:
initListeners: =>
$(".js-character-image").on "mouseover", @onCharacterHoverTimeout
$(".js-close-details").on "click", @onCloseDetailsClick
onCharacterHoverTimeout: (ev) =>
t = undefined
window.clearTimeout(t)
t = window.setTimeout(( ->
$(".js-character-details").hide()
$character = $(ev.target).closest(".js-character-image")
position = $character.position().top
$details = $character.next(".js-character-details")
$details.css("top", position)
$details.slideDown()
), 500)
$(ev.target).mouseleave ->
window.clearTimeout(t)
onCloseDetailsClick: (ev) ->
$descriptionContainer = $(ev.target).closest(".js-character-details")
$descriptionContainer.slideUp()
Now, when a visitor mouses over a character image, our code doesn't execute until after 500 milliseconds; this gives them time to move their mouse before the hover effect fires.
We also added the mouseleave
code to ensure that if the user stopped hovering over a specific character image within 500 milliseconds, the timer would reset.