blog feature image
graphics, Tech, WordPress

Navigation Menu Hover Effects with CSS Transitions in WordPress

Working on a rebuild of a site, I wanted to challenge myself with a fancier looking navigation menu than what I had done previously in WordPress, and deploy something that utilised CSS transitions to create some nifty hover effects. CSS3 comes into play here.

Edit: 7th June 2013
Recently I have found that the link contained in the menu is not working as intended in latest production releases of Chrome (v27.x), and as yet I do not know why (I swear, it used to work!). At any rate, in the chase to fix the menu I have discovered another issue with the way the divs and link items were laid out in the main menu section (essentially causing the code to be invalid markup), and therefore some of the code has changed in the example below. A fix for Chrome still eludes me. Other browsers (including Safari, Internet Explorer 10, FireFox, Opera, Chrome and Safari on iPad) remain to function as intended.

Edit: 25th June 2013
Okay, so without really doing anything, the menu is working again as expected. I am calling bug in Chrome as the culprit! Tested in v28.0.1500.52 m

Ideally I wanted to stay strictly CSS based, but as I also wanted the menu transitions to work with iPads and other tablet devices, I was forced into using some Javascript for such devices.

The results of my work, research, trial and error can be seen at a recently completed site Pipwick Marketing.

Finding the right menu

Having looked through several navigation menu tutorials I found the kind of effect I was looking for at a site I had been to previously (it has some very cool tutorials) over at tympanus.net, or more specifically their tutorial on Circle Hover Effects with CSS Transitions. It is Example 7 from this tutorial that I was trying to reproduce, which also uses 3D transforms which are not supported in some browsers (IE9 and Opera spring to mind) but seem to degrade quite nicely, and still produce some effect.

Looking through the demos and the comments at the bottom, it soon became clear that this may not so easily work “out-of-the-box” with WordPress. So this little post is about what I did to get the navigation menu I wanted, with some nifty hover effects using CSS Transitions, working in WordPress.

Investigating WordPress requirements

Let me say off the bat that for the purpose of this blog post I am using the standard Twenty Twelve theme supplied with WordPress v3.5. Using this menu style in other themes would still work (I have it working in a Method theme, for a client site, as mentioned as the example above) but there might be some differences in how you apply the code covered later in this post (in the CSS for example, what Twenty Twelve calls the #site-navigation, the nav ID of the entire menu structure, Method calls this #primary-menu). Also, I would normally make any changes to a child-theme (such as editing header.php) but the below code changes make no further reference to a child-theme.

Most of the issues I was facing were to do with matching, or coming close to matching, the structure of the HTML code as seen in the demo, versus what was naturally presented to me in WordPress.

To get close to the same structure as what the tutorial was using, allowing myself some changes considering the tutorial was based on using pure HTML code and I was going to likely be somewhat restrict by WordPress structure boundaries, I had to break new ground (for me) and inject a few levels of div classes in and around the normal structure that the Twenty Twelve theme was using.

To begin with, I tend to always use Custom Menus and for this purpose I created a few pages and menu items, whilst keeping my Blog Page as the home page. A single level menu structure (can’t see how something like this would work on multi level menus) with just 4 menu options, Home (the Blog Page), Services, About Us, and Contact Us.

Altering header.php

Keeping in mind I wanted to name things similarly to that found in the tutorial, what I ended up doing was changing the default menu code found in header.php:

<!-- begin #site-navigation -->

<nav id="site-navigation" class="main-navigation" role="navigation">

<h3 class="menu-toggle"><?php _e( 'Menu', 'twentytwelve' ); ?></h3>

<a class="assistive-text" href="#content" title="<?php esc_attr_e( 'Skip to content', 'twentytwelve' ); ?>"><?php _e( 'Skip to content', 'twentytwelve' ); ?></a>

<?php wp_nav_menu( array( 'theme_location' => 'primary',
'menu_class' => 'nav-menu' ) ); ?>

</nav>

<!-- end #site-navigation -->

To this (in both cases I have removed the tab spacing that I would normally use):

<!-- begin #site-navigation -->

<nav id="site-navigation" class="main-navigation" role="navigation">

<h3 class="menu-toggle"><?php _e( 'Menu', 'twentytwelve' ); ?></h3>

<a class="assistive-text" href="#content" title="<?php esc_attr_e( 'Skip to content', 'twentytwelve' ); ?>"><?php _e( 'Skip to content', 'twentytwelve' ); ?></a>

<?php wp_nav_menu( array( 'before' => '<div class="ch-item">
<div class="ch-info"><div class="ch-info-front"></div>
<div class="ch-info-back">','after' => '</div></div></div>',
'theme_location' => 'primary', 'menu_class' => 'nav-menu' ) ); ?>

</nav>

<!-- #site-navigation -->

What this did was give me a div structure very similar to that used in the tutorial, so I can then more easily use the CSS examples supplied to enable the menus to look how I wanted them.

Adding WordPress walker description

As also seen in the tutorial, there is a description seen of the link (eg. Home has a description, as well as a link) and I decided I wanted to implement this also. To do this, I did two things:

Within Appearance > Menus I click on Screen Options (top right) and select Description. Selecting Description allows me to write a short description of what the menu link is about. (Typically I also choose CSS Classes in this area as well. For this example, the classes I assigned were nav-menu-1, nav-menu-2, and so on, to each of the menu items).

The kicker here is, WordPress does not show this description by default (and there is no check box or any other form of UI control to make it display). We have to go back to the header.php and add a little more code, commonly known as Walker Description. This is a fairly simple matter of adding some code to the end of the menu call, as follows:

<!-- begin #site-navigation -->

<nav id="site-navigation" class="main-navigation" role="navigation">

<h3 class="menu-toggle"><?php _e( 'Menu', 'twentytwelve' ); ?></h3>

<a class="assistive-text" href="#content" title="<?php esc_attr_e( 'Skip to content', 'twentytwelve' ); ?>"><?php _e( 'Skip to content', 'twentytwelve' ); ?></a>

<?php wp_nav_menu( array( 'before' => '<div class="ch-item">
<div class="ch-info"><div class="ch-info-front"></div>
<div class="ch-info-back">','after' => '</div></div></div>',
'theme_location' => 'primary', 'menu_class' => 'nav-menu',
'walker' => new description_walker() ) ); ?>

</nav>

<!-- #site-navigation -->

Once that is added in though, we also need to add something to the functions.php as essentially we are asking the Menu to call the description_walker function.

I enabled this by using the method outlined in this blog.

Basically, I have edited functions.php and added the following:

class description_walker extends Walker_Nav_Menu
{
      function start_el(&$output, $item, $depth, $args)
      {
           global $wp_query;
           $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

           $class_names = $value = '';

           $classes = empty( $item->classes ) ? array() : (array) $item->classes;

           $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
           $class_names = ' class="'. esc_attr( $class_names ) . '"';

           $output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';

           $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
           $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
           $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
           $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';

           $prepend = '<strong>';
           $append = '</strong>';
           $description  = ! empty( $item->description ) ? '<span>'.esc_attr( $item->description ).'</span>' : '';

           if($depth != 0)
           {
                     $description = $append = $prepend = "";
           }

            $item_output = $args->before;
            $item_output .= '<a'. $attributes .'>';
            $item_output .= $args->link_before .$prepend.apply_filters( 'the_title', $item->title, $item->ID ).$append;
            $item_output .= $description.$args->link_after;
            $item_output .= '</a>';
            $item_output .= $args->after;

            $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
            }
}

Note, that without completing the above step (ie. editing functions.php) your site menu will no longer work, effectively rendering your site useless as it will error out on the “walker” menu code that has been added.

Adding the CSS

More or less this code is the same used in the Navigation Menu using CSS Transitions tutorial. The main difference will be the class used for each individual menu item (the tutorial lists them as .ch-img-1, .ch-img-2, etc. Instead, I am using .nav-menu-1, .nav-menu-2, etc and add these classes directly to the menu items via WordPress Admin > Appearance > Menus).

But, if using the Twenty Twelve theme then you should be able to copy and paste the below into your style.css ( placed all of this below the “@media screen and (min-width: 960px)” section of the style.css) :

/* =Custom Nav
----------------------------------------------- */

#site-navigation ul a {
    display: block;
    position: relative;
}

#site-navigation ul li {
    position: relative;
    z-index: 40;
    font-size: 11px;
	font-weight: bold;
    text-transform: uppercase;
    margin-right: 21px;
    border-left: none;
}

#site-navigation.main-navigation { padding-bottom: 10px; }

#site-navigation .nav-menu {
	margin: 0;
	padding: 0;
	list-style: none;
	display: block;
	text-align: center;
	width: 100%;
}

#site-navigation .nav-menu:after,
#site-navigation .nav-menu:before {
	content: '';
    display: table;
}

#site-navigation .nav-menu:after {
	clear: both;
}

#site-navigation .nav-menu li {
	width: 160px;
	height: 160px;
	display: inline-block;
}

#site-navigation .nav-menu {
	width: 100%;
	height: 100%;
	border-radius: 50%;
	position: relative;
	cursor: default;
	-webkit-perspective: 900px;
	-moz-perspective: 900px;
	-o-perspective: 900px;
	-ms-perspective: 900px;
	perspective: 900px;
	z-index: 999;
}
#site-navigation .ch-info {
	position: absolute;
	width: 100%;
	height: 100%;
	-webkit-transform-style: preserve-3d;
	-moz-transform-style: preserve-3d;
	-o-transform-style: preserve-3d;
	-ms-transform-style: preserve-3d;
	transform-style: preserve-3d;
}
#site-navigation .ch-info > div {
	display: block;
	position: absolute;
	width: 100%;
	height: 100%;
	border-radius: 50%;
	background-position: center center;
	-webkit-transition: all 0.4s linear;
	-moz-transition: all 0.4s linear;
	-o-transition: all 0.4s linear;
	-ms-transition: all 0.4s linear;
	transition: all 0.4s linear;
	-webkit-transform-origin: 50% 0%;
	-moz-transform-origin: 50% 0%;
	-o-transform-origin: 50% 0%;
	-ms-transform-origin: 50% 0%;
	transform-origin: 50% 0%;
}

#site-navigation .ch-info .ch-info-front {
	box-shadow: inset 0 0 5px 2px rgba(74,103,139,0.7);
}

#site-navigation .ch-info .ch-info-back {
	-webkit-transform: translate3d(0,0,-160px) rotate3d(1,0,0,90deg);
	-moz-transform: translate3d(0,0,-160px) rotate3d(1,0,0,90deg);
	-o-transform: translate3d(0,0,-160px) rotate3d(1,0,0,90deg);
	-ms-transform: translate3d(0,0,-160px) rotate3d(1,0,0,90deg);
	transform: translate3d(0,0,-160px) rotate3d(1,0,0,90deg);
	background: #000;
	opacity: 0;
}

#site-navigation li.nav-menu-1 .ch-info-front {
	background-image: url(images/menu_home1.png);
	background-repeat: no-repeat;
}

#site-navigation li.nav-menu-2 .ch-info-front {
	background-image: url(images/menu_services.png);
	background-repeat: no-repeat;
}

#site-navigation li.nav-menu-3 .ch-info-front {
	background-image: url(images/menu_about.png);
	background-repeat: no-repeat;
}

#site-navigation li.nav-menu-4 .ch-info-front {
	background-image: url(images/menu_contact.png);
	background-repeat: no-repeat;
}

#site-navigation ul.nav-menu .ch-info a span {
	display: block;
	width: 140px;
	color: #FFF;
	font-style: italic;
	margin: 0px auto;
	font-size: 10px;
	line-height: 11px;
	font-weight: 300;
	text-transform: none;
	word-wrap: break-word;

}

#site-navigation ul.nav-menu .ch-info a {
	display: block;
	color: #FFF;
	text-transform: uppercase;
	font-style: normal;
	font-weight: 700;
	text-transform: uppercase;
	font-size: 14px;
	margin: 0 15px;
	padding: 40px 0 0 0;
	height: 38px;
	letter-spacing: 1px;
	font-family: "Droid Serif", "Georgia", serif;
	border-bottom: 1px solid rgba(255,255,255,0.5);
	text-shadow:
		0 0 1px #FFF,
		0 1px 2px rgba(0,0,0,0.3);

}

#site-navigation ul.nav-menu .ch-info a:hover {
	color: #04bfbf;
}

#site-navigation .ch-item:hover .ch-info-front {
	-webkit-transform: translate3d(0,220px,0) rotate3d(1,0,0,-90deg);
	-moz-transform: translate3d(0,220px,0) rotate3d(1,0,0,-90deg);
	-o-transform: translate3d(0,220px,0) rotate3d(1,0,0,-90deg);
	-ms-transform: translate3d(0,220px,0) rotate3d(1,0,0,-90deg);
	transform: translate3d(0,220px,0) rotate3d(1,0,0,-90deg);
	opacity: 0;
}

#site-navigation .ch-item:hover .ch-info-back {
	-webkit-transform: rotate3d(1,0,0,0deg);
	-moz-transform: rotate3d(1,0,0,0deg);
	-o-transform: rotate3d(1,0,0,0deg);
	-ms-transform: rotate3d(1,0,0,0deg);
	transform: rotate3d(1,0,0,0deg);
	opacity: 1;
}

Note: at about lines 102 through to 120 in the CSS, I have added in some images to the front of the menu links. You will either need to create/obtain some images similarly named, or replace this code with something else before it will appear “right”.

Phew! With all of that in place, I had my new navigation menu in place also using CSS transitions (and also in this case, 3D transforms). Check out how it looks here.

After checking it out on various browsers, of course I then went to my iPad to have a look at (and admire it) there. To find that it was broken.

Get it working on an iPad

Looking through the comments on the tutorial site itself, I noticed someone mentioned getting it to work on an iPad and using jQuery to do this. When using WordPress though, you also then have to figure out what the best method is of getting jQuery to work, and not mess up any plugins that might also require it.

By finding this blog post though, I was able to implement jQuery into my WordPress site.

Basically I needed to add the following into my functions.php:

/*
Enques jQuery from Google CDN.
Uses the currently registred WordPress jQuery version.
*/
function appglobe_jquery_enqueue() {

   /*
   Probably not necessary if called with the 'wp_enqueue_scripts' action.
   */
   if (is_admin()) return;

   global $wp_scripts;

   /*
   Change  this flag to have the CDN script
   triggered by wp_footer instead of wp_head.
   If Google CDN is unavailable for some reason the flag
   will be ignored and the local WordPress
   jQuery gets enqueued and included in the head
   by the wp_head function.
   */
   $cdn_script_in_footer = false;
   /*
   Register jQuery from Google CDN.
   */
   if (is_a($wp_scripts, 'WP_Scripts') && isset($wp_scripts->registered['jquery'])) {
      /*
      The WordPress jQuery version.
      */
      $registered_jquery_version = $wp_scripts -> registered[jquery] -> ver;

      if($registered_jquery_version) {
         /*
         The jQuery Google CDN URL.
         Makes a check for HTTP on top of SSL/TLS (HTTPS)
         to make sure the URL is correct.
         */
         $google_jquery_url = ($_SERVER['SERVER_PORT'] == 443 ? "https" : "http") .
         "://ajax.googleapis.com/ajax/libs/jquery/$registered_jquery_version/jquery.min.js";

         /*
         Get the HTTP header response for the this URL, and check that its ok.
         If ok, include jQuery from Google CDN.
         */
         if(200 === wp_remote_retrieve_response_code(wp_remote_head($google_jquery_url))) {
         wp_deregister_script('jquery');
         wp_register_script('jquery', $google_jquery_url , false, null, $cdn_script_in_footer);
         }
      }
   }
   /*
   Enqueue jQuery from Google if available.
   Fall back to the local WordPress default.
   If the local WordPress jQuery is called, it will get
   included in the header no matter what the
   $cdn_script_in_footer flag above is set to.
   */
   wp_enqueue_script('jquery');
}
add_action('wp_enqueue_scripts', 'appglobe_jquery_enqueue', 11);

I pasted the above into the bottom of functions.php.

Then, following the instructions of one of the tutorial comments, I pasted the following into my footer.php, just above the closing body tag:

<script type="text/javascript">
$(function(){
$('.ch-item').bind('mouseenter mouseleave tap', function(e){});
});
</script>
Edit: 10th February 2014The above code in the footer used to say “$(‘.ch-item’).bind(‘hover’, function(e){});” but has been changed since jQuery v1.9.0 stopped supporting the hover event. If using v1.8.3 or older of jQuery then the old code should still work.

Go and check on iPad again and … it works! Double phew!

NOTE: the end result of this is that jQuery is getting loaded in the head section of the page, prior to other javascript loads called upon by the WordPress theme or by various plugins. So, if you are NOT looking to get this to load into WordPress (but merely wish to get it working on an iPad) then what you need to do is call jQuery in the head section, and then call the function just above the closing body tag.

That means, copy and paste this into the head section, assuming you are not already calling jQuery:

<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js'></script>

and copy and paste the following just above the closing body tag at the bottom of the page:

<script type="text/javascript">
$(function(){
$('.ch-item').bind('mouseenter mouseleave tap', function(e){});
});
</script>
Edit: 10th February 2014The above code used to say “$(‘.ch-item’).bind(‘hover’, function(e){});” but has been changed since jQuery v1.9.0 stopped supporting the hover event. If using v1.8.3 or older of jQuery then the old code should still work.

I hope this has helped someone out, but if you find any anomalies (or something generally not working) then please feel free to leave a comment below.

Please share:

17 comments on “Navigation Menu Hover Effects with CSS Transitions in WordPress

  1. Hi Adrian, I wonder if I could tap into your expertise and see if you could help me?
    I also love this circle hover effect and have set it up on my site. It works fine on PC and Mac but I can’t get it to work on the iPad. I don’t need to modify it for WordPress, just standard a html page. But I can’t work out where to add the following script to make it work on iPads:

    $(function(){
    $('.ch-item').bind('hover', function(e){});
    });

    I’d be very grateful if you could tell me exactly where I need to add it. Much appreciated Jamie

    • Hi Jamie

      Thanks for stopping by!

      Have you got jQuery loading into your site? Although this is done in a far more convoluted manner in WordPress, you will still need to call jQuery when coding into HTML.

      The function can then be inserted in one of two ways:
      Manually place the code in your site between some script tags
      Or, put the function in an external .js file and call that from within the HTML

      Either way, your first step is to call on jQuery. Do you know whether that is happening?

  2. thank you for the tip!!! finally got it working on mobile browsers! i found that connecting to jquery via

    without the http was what was holding me up

    s c r i p t src=”//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js” wouldnt work. stumped me, but who cares now! it’s working! thanks again.

    • Hi Kate, I’m glad it worked out for you.
      Have you tested this and got it working in Chrome as well? That bit still has me stumped (I only just got around to posting the question on the Chrome forums)

        • Thanks Kate, had a peek (looks fantastic!). I think my issue lies in trying to implement it in WordPress. All of the demos from the original site work just fine in Chrome, but I haven’t tried to get it working in anything other than WordPress. It seems the search continues!

  3. Hi, I hope you’re still around. I can’t seem to get this working on an iPad for the life of me. I added the code into functions.php and then called the jquery in footer before closing body tag. Didn’t work. Then deleted all of that then added the googleapi code to the header and called the jquery in the footer again – no luck 🙁 What happens is when I tap the circle, nothing happens, but when I hold it down, the hover appears but then iPad attempts to copy/select it then I let go and the hover disappears and the copy handles are there….holding onto thin air. I spent all mornign implementing this onto my homepage, and it would suck if it didn’t work on iPad, then I will need to look for another solution or recode.

    • Actually, now what’s happening is that…sometimes it binds. I have a total of 16 circles on a 4×4 grid and when I click on one square, the hover for another pops up. strange, must be the responsive css…. Thanks anyway. :)!!

      • Hello Myles, thanks for your responses.

        Certainly still about, just let me know if you want me to have a look and try and help troubleshoot it with you.

        I have the original demo site and soon to be launched new client site both working as expected on an iPad (albeit, not in a 4×4 grid) so off the top of my head I would think maybe if there is not enough space in the grid, the hover effect of one circle might be messing with the one immediately below it.

        My first guess would be to perhaps implement some z-index settings, requiring you add classes to each row in the grid (or something along these lines).

  4. Hi Adrian, can you help me?
    I also love this circle hover effect and have set it up on my site. I don’t need it for WordPress, but I can’t get it to work on the iPad and iphone4 using the suggestions above. Please help!

    angelaschmidtdesign.com

    • Hi Angela, I will help any way I can!

      So, just to be clear you are trying to get the hover effects working on iPad / iPhone and are having troubles there, can you give me the URL of the site that you have tried to implement the menu on? You may want to reconsider using this style of menu for mobile devices (I typically find the circles “too big” and switch to a jump menu for smaller mobile devices), but of course, that’s up to you.

      For the iPad it should be a matter of getting the JavaScript loaded but if you can start off with the URL then I can at least check that all is working as expected on PC / Mac.

        • Hi Angela, looks to be all working on iPad (right now I can test on my first generation iPad, but my 4th generation is not with me right now). I don’t own an iPhone myself to be able to test it there.

          Interestingly I found that, with my original example, the menu was no longer working on iPad when using an older version of the jQuery library (the test site was auto loading the most recent version) but since forcing it to use v1.8.3 (as you are doing in your site) the test site works again. I suspect it will work in iPhone also, but won’t be able to test that for 24 hours or so.

        • Hi Angela, something else I found today that might be of note to you, and that is that v1.8.3 of jQuery is the last version to support the hover event. It has been replaced with ‘mouseenter mouseleave’ and I have added a Note to the original article explaining this. I know you are currently using v1.8.3 of jQuery but just thought it worth mentioning in case you went to a newer version (latest stable is 1.10.2)

          • Thank You. All seems to work great except for a conflict on an android tablet with the mobile menu. The icons will not work, but I can press and hold and it will show up — not user friendly! Any thoughts? Thanks.

Leave a Reply

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

Notify via Email Only if someone replies to My Comment