WordPress and HoverIntent

fixing spastic menus…

The Problem

Don’t you just love all those web sites with pull-down and fly-out menus that unexpectedly flash in your face when you don’t want them, and then disappear when you do want them? Let’s face it: our mouse movements are never perfect, and hover events need to take this into account to avoid irritating the user.

The Fix

The easy fix is a neat little jQuery plug-in called hoverIntent, by Brian Cherne. What it does is add a little delay the mouseOver event, and optionally the mouseOut event, waiting until the user has definitely hovered, or un-hovered, the menu. In effect, it “eats” unintended mouse events. The effect is nice—no more flashing unexpected menus in your face, and no more menus that fly away while you’re trying to use them. Try it on the menu above and see the effects.

Using hoverIntent for WordPress Nav Menus

I’ve used hoverIntent before on hand-made sites, but recently I decided to put it in my WordPress site. But Not So Fast! The way WordPress builds pages has a rather steep learning curve. First of all, you can just edit the header.php file of your theme and put in the link to load the hoverIntent script, followed by some jQuery in a document.ready handler (just under wp_head() ) to make hoverIntent work on the desired menu, in the desired ways:

The Usual Way

<script type='text/javascript' src='/path/to/jquery.min.js'></script>
<script type='text/javascript' src='/path/to/hoverIntent.min.js'></script>
<script type='text/javascript'>
jQuery(document).ready(function(){
  jQuery('.menu ul li').hoverIntent({over:navover, out:navout, timeout:400});
  function navover(){jQuery(this).children('ul').fadeIn('slow');}
  function navout(){jQuery(this).children('ul').fadeOut('fast');}
});
</script>

Something like that will get it going, after you have disabled the :hover effects in the nav menu portion of your CSS file. But is that really the right way to do it in WordPress? Well… no.

The WordPress Way

WordPress has built-in ways of handling the dependencies and proper load-order of things, so we should do it the WordPress way, which is to make a couple functions in functions.php and then tell it to “enqueue” the hoverIntent script (that comes with WordPress), and also load the instantiation in the head section of the generated page to tell hoverIntent what to do.

I couldn’t find any applicable examples on-line, so after many hours of fiddling I ended up with this, which goes in functions.php in your template:

// make a little function to enqueue hoverIntent:
function enq_hoverIntent() { wp_enqueue_script('hoverIntent'); }
// now make WP run it:
add_action('wp_enqueue_scripts', 'enq_hoverIntent');

// enclose some jQuery script in a php function:
function init_hoverIntent() { ?>
<script type='text/javascript'>
  jQuery(document).ready(function(){
    jQuery('.menu ul li').hoverIntent({
      over : navover,
      out : navout,
      timeout : 400
    });
    // (how to use both fade and slide effects!):
    function navover(){
      jQuery(this).children('ul')
        .stop(true,true)
        .fadeIn({duration:600,queue:false})
        .css('display','none')
        .slideDown(600);
    }
    function navout(){
      jQuery(this).children('ul')
        .stop(true,true)
        .fadeOut({duration:300,queue:false})
        .slideUp(300);
    }
  });
</script>
<?php }
// now make WP load that into the head section of the html page:
add_action('wp_head', 'init_hoverIntent');

And that’s it! Assuming you already have a working CSS-based drop-down or fly-out menu in your header.php file, you don’t need to add anything else to it. WordPress will now load hoverIntent at the right place (and it will also load jQuery, if not already loaded). And when it runs wp_head() it’ll add your initialization script that ties hoverIntent to your nav menu.

Notes

  1. You need to study your document tree a bit to see what tags, IDs, and classes your nav menu uses, which will vary with different themes.
  2. You can’t use $ for jQuery in WordPress—it loads it in “noConflict” mode.
  3. Be sure your CSS (1) hides the sub-menu ULs on page-load, but (2) doesn’t show them on :hover, as that would override the effect and you’ll think it isn’t working.
  4. If you have not defined a custom menu in WordPress Admin, WP will use wp_page_menu() to build the menu when wp_nav_menu() is called. The menu will be built in levels according to the parent and menu order settings of all your pages.
  5. The hoverIntent “timeout” setting refers to the mouseOut delay, which defaults to 0, so you need to instantiate it as shown above to use timeout. 400 (milliseconds) is a decent setting to keep the menu open while you are navigating it and cutting corners along the way.
  6. Since we now have jQuery handy, we might as well add some nice animation to the menu. We could just use show() and hide(), but it’s much more pleasing to use slideDown() slideUp(), or fadeIn() fadeOut(), or even better, both! We could even use jQuery animate() to make the menu display in other neat ways by animating various CSS properties of the drop-down ULs.

—KV5R

2 thoughts on “WordPress and HoverIntent
  1. Hi Bryan!
    Ummm, I don’t remember! ;-? !! It’s been a while!

    I don’t know exactly how to answer your post, just do like the example and fight with it til it works..
    1. hoverintent comes with WP, you just need to make it load it
    2. add_action loads it, I didn’t have to ‘register’ it with WP.
    You just need to make a function and then run it..
    Then make another function with jQuery in php and run that; WP will pop that script in the head and run it on every page load.

  2. Hey this is exactly what I was looking for! For those of us who are really stupid I’m assuming hoverIntent needs to first be registerd in functions.php??

    Using your example above and assuming all the tags/ids/classes are being used properly, would this be the correct way to register hoverintent with your function to get it completly working?

    1) Place hoverintent in js or similar folder

    2) Register script in functions.php with other scripts:

    wp_register_script( ‘hoverIntent’, get_template_directory_uri().’/js/jquery.hoverIntent.js’,array(‘jquery’),null,true);

    3) Add your code to end functions.php

    // make a little function to enqueue hoverIntent:
    function enq_hoverIntent() { wp_enqueue_script(‘hoverIntent’); }
    // now make WP run it:
    add_action(‘wp_enqueue_scripts’, ‘enq_hoverIntent’);

    // enclose some jQuery script in a php function:
    function init_hoverIntent() { ?>

    jQuery(document).ready(function(){
    jQuery(‘.menu ul li’).hoverIntent({
    over : navover,
    out : navout,
    timeout : 400
    });
    // (how to use both fade and slide effects!):
    function navover(){
    jQuery(this).children(‘ul’)
    .stop(true,true)
    .fadeIn({duration:600,queue:false})
    .css(‘display’,’none’)
    .slideDown(600);
    }
    function navout(){
    jQuery(this).children(‘ul’)
    .stop(true,true)
    .fadeOut({duration:300,queue:false})
    .slideUp(300);
    }
    });

    <?php }
    // now make WP load that into the head section of the html page:
    add_action('wp_head', 'init_hoverIntent');

Leave a Reply

Your email address will not be published. Required fields are marked *