A Really Nice Way To Handle Popup Information

Published by Chris Coyier

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;
  -webkit-transition: opacity 0.3s ease-out;  
     -moz-transition: opacity 0.3s ease-out;  
      -ms-transition: opacity 0.3s ease-out;  
       -o-transition: opacity 0.3s ease-out;  
          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.