Doug Neiner gave a fantastic talk at this year’s Front End Design Conference. He covered a lot of stuff there, which you can see in his slides, but I’d like to highlight one thing in particular: the way he handled popup information in the demo. I’m going to try and re-explain it…
Let’s say our goal is this: hover over an image to display extra information (like the title of the image and a URL).

Pretty darn simple design pattern right? Well, not really. There are a lot of subtle things to consider. Let’s start from the simplest possible way and improve it.
Simplest way: hide/show with CSS
If our markup is:
<figure>
<img src="image.jpg" alt="cool image">
<figcaption>
<h3>Cool Image</h3>
<a href="http://coolplace.com">http://coolplace.com</a>
</figcaption>
</figure>
We’ll use the <figcaption>
as the popup info. We’ll hide it by default, then display it when the image is rolled over:
figcaption {
display: none;
}
figure:hover figcaption {
display: block;
}
But… it’s so abrupt.
Fade in/out
We can chill it out with CSS transitions.
ficaption {
opacity: 0;
transition: opacity 0.3s ease-out;
}
figure:hover figcaption {
opacity: 1;
}
We could get even fancier there if we wanted by applying different durations.
But… popups come up even if we are just quickly moving our mouse past and likely not interested in seeing popups.
“Hover Intent”
If we get JavaScript involved, we can get a little fancier. There is a jQuery plugin called hoverIntent which can be useful in preventing unwanted hover behavior. It imparts a bit of a delay before an event is fired, so quickly mousing over things won’t trigger a popup but slowing down and stopping on an image will.
You could apply that like this:
$("figure").hoverIntent(function() {
$("figcaption", this).fadeTo(400, 1);
}, function() {
$("figcaption", this).fadeTo(400, 0);
});
But… now all the images use hoverIntent, which means that the slight delay to see the popup can be very annoying if you are specifically trying to browse the images and see the information. As Doug put it “my brain can think faster than that.”
And finally: The Really Nice Way (doTimeout)
We like first part of hoverIntent, where quick mouseovers don’t trigger the popup, but once we trigger one popup we want subsequent popups to happen quickly with no delay. If the user leaves the image area for a little bit, the delay is imparted again.
This makes use of the doTimeout plugin by Ben Alman. Admittedly, this gets a bit complex:
var li_cache, over = false;
$( "figure" )
.delegate( "figcaption", "mouseenter", function ( e ) {
var $li = $( this ), speed;
if ( li_cache === this && over ) {
$.doTimeout( "hoverOut" );
return;
}
if ( over ) {
$.doTimeout( "hoverOut", true );
speed = 0;
} else {
$.doTimeout( "hoverOut" );
speed = 500;
}
$.doTimeout( "hoverIn", speed, function () {
over = true;
$li.find( "div" ).fadeTo( 200, 1.0 );
});
})
.delegate( "figcaption", "mouseleave", function ( e ) {
var $li = $( this );
$.doTimeout( "hoverIn" );
$.doTimeout( "hoverOut", 500, function () {
over = false;
$li.find( "div" ).stop( true ).fadeOut();
});
});
Super nice. This improves the popup information reveal in such a natural and subtly enjoyable way that it’s kind of a shame it’s so difficult to implement. But it’s worth it.
Doug’s GitHub Repo
Go grab the GitHub Repository for this. Doug did a great job putting this together and it’s educational as heck. You can see the progression through all the different hover functionalities just by commenting/uncommenting some function names. Beyond that, this example covers using jQuery templating, “Mockjax” (hijacking AJAX requests for local development) and more.
Seriously, I’m not even going to post a live demo, go download his repo and open the index.html file in a browser.
Even if i understand that it’s simplier to do it in JS, you can also
#1. put a timeout to add a classname after a few hundreds milliseconds.
#2. use CSS animations with 0% to 30% to do nothing and 30% to 100% to do the needed animation (which could then be hardware accelerated, which JS is not)
#3. User transition-delay.
Yeah check out transition-delay http://www.w3.org/TR/css3-transitions/#the-transition-delay-property-
That’s cool guys and thanks for re-iterating that (I mentioned it briefly in the article), but it’s not quite the same or as elegant as the final example by Doug.
The difference is that only the first hover has the delay and subsequent hovers do not, unless you leave the area for a bit.
That’s the whole beauty of this thing.
hehehe…
may be this is false…
http://jsbin.com/orineq
You have writen twice ficaption.
Great tutorial and some good ideas.
I’m a little conflicted on implementing hover conventions because of the touchscreen interaction model.
Before the iPad I was a big proponent of hover menus and other hover conventions, but now I find that hover causes the user experience to be less fluid for touchscreen users.
Nice, thanks Chris.
As someone who is pretty amateur at jQuery, it’d be cool if in some of your future code snippets you could include one or two inline comments around the important bits to help understand what those lines are doing.
Cheers
Nice! Note you can produce the same effect as hoverIntent with the transition-delay property, e.g.:
I mentioned transition delay briefly in the article but it suffers from the same problem that hoverIntent does: it applys on every single mouseover.
The really cool thing that Doug did was apply the delay for the first hover, then remove the delay for subsequent hovers.
Chris, YOUR last name should be “Rock”. Cause you do!
On another note and completely off-topic. Is their some way to chain pseudo-classes. Kinda like this:
That should be a question mark: “… to chain pseudo-classes?“
Or worse yet is this possible:
What cnwtx mentioned
p:after:before
is not possible yet.Excellent post!
Thank you, you have been most helpful.
Can you please provide a demo.
Thanks
Download the GitHub repo linked to at the bottom of the article. Open the index.html file in a browser. This is Doug’s work, I want to make sure he has 100% control over what people see.
Nice technique, and great timing for me:
I’ve been struggling trying for pretty much this effect for a client’s site. This looks both simpler to implement and much more “finished” and professional that other techniques I’ve tried.
Thanks for this, Chris.
This was really easy to follow, cheers
Couldn’t actually get it to work for a while but that was just me being special
Thanks again
I like that you provided some alternative techniques for doing that. I used a lot in some of my projects hoverIntent but it’s not most suitable for this situation.
I really like this site : http://frontenddesignconference.com/
So sick idea ! <3 i love it
Cool Stuff Chris, thanks for sharing.
You have a typo under the first CSS Section:
ficaption { /*figcaption */
display: none;
}
Feel free to delete this comment, just wanted to let you know.
AG
Or, you see, you could use this:
Add some easing and you have basically very same thing, with much less code.
Thanks for sharing code =)
But for the record it’s not really the same. That code, when figcaptions are hovered it stops and current animations then animates them in or out.
The final code presented here does much more. It doesn’t trigger the animation right away, there is a delay. But that delay is only present the first time you mouse into that area. Subsequent hovers aren’t subject to the delay, unless you leave the area for a while and came back.
I just wanted to make this very clear, as the whole point of this article is improving this simple interaction in subtle but important ways.
Very interesting article Chris. This one’s definitely going in my bookmarks for future reference.
Great post, thank you.
I’m implementing this for a featured image grid in WordPress – my pop-ups are wider than the image used as the trigger, and absolutely positioned off to the right a bit (intentionally to match a design). Used as a non-moving tooltip, if you will. What’s happening though, is the pop-up for the image furthest to the right side of the grid, gets cut off (partially hidden) and then adds a horizontal scrollbar by the image grid container element.
It seems to be caused by using overflow:auto; in the container element, but that’s required for the sticky footer to function. http://www.cssstickyfooter.com/
Any tips on how I can force the pop-up to show above all content, including the container?
I’ve tried overflow and z-index, but it’s still inside / underneath / cropped.
Thank you for your thoughts.
If you want to do it even more right, or if you were thinking that the basic mechanism would be a good fit for things like menus — and especially menus with submenus — then you need to use this: https://github.com/kamens/jQuery-menu-aim