A while ago we covered a cool “hover” technique by Doug Neiner where an informational popup was displayed when you hovered over a picture. The first time you hovered over, there was a delay. This was to prevent accidental or fly-by mouse overs, as opposed to intentionally focusing on a particular picture. Subsequent hovers showed the popup immediately. The idea being that you’re already in that exploratory mode.
Doug used jQuery for the animations and some fancy dancing to keep track of the hover state and how it should be behaving. Let’s do it a bit of a different way using CSS transitions with delays, and then just a touch of jQuery to keep track of the state.
Use Case
Let’s say you have a row of functionality buttons. Users can click the button, or use a keyboard command that triggers the function. Power users love keyboard commands but need to learn them first and sometimes need reminders. So you decide to go with some kind of popup that will show the command when the button is hovered.
But mobile devices don’t have hover!! Correct, or keyboards such that keyboard commands would be useful in this use case.
Title attribute?
One way you could go is a title attribute.
<a href="#" class="function button" title="⌘G">Do Thing</a>
This is a totally decent way to go. You’ll get a standard title popup like this when hovered over:
In fact, the default behavior of title attribute is just as we described. The first hover will take a little bit to reveal the popup, but other links hovered over quickly will reveal right away, until enough time is given for the active popup to fade away completely.
Nice. But… no design control (c’mon shadow DOM!), no specific functionality control, and as you’ll see in a moment, no generated content allowed.
By hand
Instead lets hand-roll this thing. We’ll put the command right in the markup:
<nav>
<a href="#" class="button">
Cut
<span class="command">
<span class="screen-reader-text">Keyboard Command:</span>
<span class="mod">X</span>
</span>
</a>
...
</nav>
This way we will:
- Show nothing but the button for mobile
- Be able to show the key command on hover for desktop
- Announce what the random letter does (it’s a keyboard command) for screen readers
- Apply the correct modifier key without changing markup
- Keep it reasonably semantic
Transition delay: delay on / instant off
Now that we have markup to work with, you can style up the look of the popup information however you need.
.button {
/* Button styling */
position: relative;
}
.command {
/* Popup styling */
position: absolute;
opacity: 0; /* Not shown by default */
}
Functionally, we’ll apply a one-second delay before showing the popup (keep annoyingness down) but instantly remove the popup when hovering away. We learned all about this one time.
.command {
transition: opacity 0.2s 0 ease; /* Mouse leave: immediate */
}
.button:hover .command {
transition: opacity 0.2s 1s ease; /* Mouse enter: delay */
}
The above is unprefixed, but remember to use -webkit-, -moz-, -ms-, and -o- for transitions. Or use Compass and do @include transition(opacity 0.2s 0 ease);
Transition delay delay: instant only when focused
The above CSS gets us half way there, but it will apply the delay to every hovered button. That means exploring all the shortcuts is slow, tedious, and offends our faster-moving brains. We want to remove the delay once we’ve proven we’ve been inside the navigation area with our mouse long enough.
Using jQuery, we’ll apply classes to the nav element depending on how we want it to behave. On entry to the navigation area, we wait one second, and then apply a class of “immediate”. On exit, we remove that class.
$("nav").hover(function() {
/* Mouse enter */
var nav = $(this);
setTimeout(function() {
nav.addClass("immediate");
}, 1000);
}, function() {
/* Mouse leave */
$(this).removeClass("immediate");
});
nav.immediate .command {
transition-delay: 0s !important;
}
We just need to get a hair fancier by applying and removing an “out” class. This is so if a user mouses on for half a second and out, the timeout will still trigger and give the immediate class, but the out class will negate it. Here’s the complete JS:
$("nav").hover(function() {
/* Mouse enter */
var nav = $(this).removeClass("out");
setTimeout(function() {
nav.addClass("immediate");
}, 1000);
}, function() {
/* Mouse leave */
$(this)
.addClass("out")
.removeClass("immediate");
});
With the “out” class, the delay is restored:
nav.out .command {
transition-delay: 1s !important;
}
Demo and Download
I put the demo on CodePen. If you want to download a copy you can click the Share button and click “Export as .zip”.
Notes
The CodePen demo has the bit of JavaScript that applies the “mac” or “pc” class that applies the modifier key. Warning: gross UA testing. But is there any other way to do it?
There is a bug (or it seems to me is a bug) in OS X Voice Over that reads the buttons as:
⌘ Cut Keyboard Command:X
rather than:
Cut Keyboard Command: ⌘X
Where the psuedo element is specifically being applied. Even better would be:
Cut [quick pause] [soft voice]Keyboard Command: ⌘X[/end soft voice]
Maybe, anyway.
You could also make the
transition-delay: 0s
with a selectornav.immediate:not(.out) .command
so you don’t have to set the delay for the.out
class again and you could even leave this.out
thing completely, if you reset the timeout when leaving, I think :)Btw, in the demo the key for windows is CTRL+X/C/V, not ALT ;-)
Just about to say this too. :)
If only there was a state of html element, toggled by hovering it for 2s+and accessed via
:long-hovered
pseudoclass…Imagine:
:P
Nice.
Just interested how voice over reads ⌘
very nice Nick… i just tried that and worked like a charm! kudos to you for sharing your knowledge with us…
This is pretty awesome thanks for sharing.
No need to mess around with the
out
class.Just cancel the timeout on mouseleave: http://codepen.io/JosephSilber/pen/2/2
very nice. thank you for share …
ease-in-out has the most attractive, is not it?
Very nice, just a shame there’s so much mark up required.
The markup was specific to this use cae, but the “state” concept would work with any hover/reveal situation.
I don’t know why my previous link to CodePen was 404’ed, but here’s a new one: http://codepen.io/JosephSilber/pen/2/2
It’s a pity we can’t edit comments here, Chris. Feel free to combine my two comments (you might also wanna fix my typo (mouseleave, with an ‘e’).
The animations that can be achieved with css3 and jquey are fantastic. To think that not long ago, if you wanted a cute animation had to do everything in flash, etc..! Even a simple gradient had to do a picture. The css3 are translations with the best of these last years.
I recently had to test with html5 and css3, the translations and transformations saved my life.
Regards.
There’s no reason to use javascript for this effect at all; it can be done entirely in CSS! See my example codepen (http://codepen.io/telic/details/1/1)
Very cool, great work.
Thanks – very cool
what about transition delay delay delays ? :)
Absolutely great work !!! Thumbs up!!!
What is the use of the
!important
marker in your example?