Long Hover

Avatar of Chris Coyier
Chris Coyier on

I had a very embarrassing CSS moment the other day.

I was working on the front-end code of a design that had a narrow sidebar of icons. There isn’t enough room there to show text of what the icons are, so the idea is that we’ll use accessible (but visually hidden, by default) text that is in there already as a tooltip on a “long hover.” That is, a device with a cursor, and the cursor hovering over the element for a while, like three seconds.

So, my mind went like this…

  1. I can use state: the tooltip is either visible or not visible. I’ll manage the state, which will manifest in the DOM as a class name on an HTML element.
  2. Then I’ll deal with the logic for changing that state.
  3. The default state will be not visible, but if the mouse is inside the element for over three seconds, I’ll switch the state to visible.
  4. If the mouse ever leaves the element, the state will remain (or become) not visible.

This was a React project, so state was just on the mind. That ended up like this:

Not that bad, right? Eh. Having state managed in JavaScript does potentially open some doors, but in this case, it was total overkill. Aside from the fact that I find mouseenter and mouseleave a little finicky, CSS could have done the entire thing, and with less code.

That’s the embarrassing part… why would I reach up the chain to a JavaScript library to do this when the CSS that I’m already writing can handle it?

I’ll leave the UI in React, but rip out all the state management stuff. All I’ll do is add a transition-delay: 3s when the .icon is :hover so that it’s zero seconds when not hovered, then goes away immediately when the mouse cursor leaves).

A long hover is basically a one-liner in CSS:

.thing {
  transition: 0.2s;
}
.thing:hover {
  transition-delay: 3s; /* delay hover animation only ON, not OFF */
}

Works great.

One problem that isn’t addressed here is the touch screen problem. You could argue screen readers are OK with the accessible text and desktop browsers are OK because of the custom tooltips, but users with touch-only screens might be unable to discover the icon labels. In my case, I was building for a large screen scenario that assumes cursors, but I don’t think all-is-lost for touch screens. If the element is a link, the :hover might fire on first-tap anyway. If the link takes you somewhere with a clear title, that might be enough context. And you can always go back to more JavaScript and handle touch events.