Create animated menu with CSS Sprites and jQuery

In this blog post we'll create a simple Animated Menu using CSS Sprites & jQuery. Some of you might remember the times when you needed to download custom javascript scripts designed just for a certain type of menu. Nowdays you can very easily create your own custom menus. Let's see how.

Nothing really special, but can easily be extended to meet your needs. Also, I decided to use background-position animations because it's not that common to find them online. And they're certainly not common like fade-type animations.

This is a main sprite image we'll use:

The HTML

Enough talk, let's get to it. First, we'll start with the HTML. We'll use HTML 5 elements, such as menu and nav. Remember, HTML 5 site uses a new & cool doctype:

<!DOCTYPE html>

HTML for menu:

<!-- Menu Start -->
<menu>
 
    <!-- Navigation Start -->
    <nav>
        <ul id="menu">
            <li class="home"><a class="main" href="#">Home</a></li>
            <li class="about"><a class="main" href="#">About</a></li>
            <li class="blog"><a class="main" href="#">Blog</a></li>
            <li class="videos"><a class="main" href="#">Videos</a></li>
            <li class="contact"><a class="main" href="#">Contact</a></li>
        </ul>
    </nav>
    <!-- Navigation End -->
     
    <!-- Form Start -->
    <form action="index.php" method="get">
        <input id="search" type="text" name="query" />
        <a href="#">Search</a>
    </form>
    <!-- Form End -->
     
</menu>
<!-- Menu End -->

The CSS

Now, let's add some CSS:

body {
    margin: 0;
    padding: 20px;
    font-family: Verdana;
}
 
menu, nav {
    display: block;
    float: left;
    margin: 0;
    padding: 0;
}
 
menu {
    width: 980px;
    background: black url('images/main-bg.png') right top;
}
 
menu ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
    font: normal 14px/14px Verdana;
}
 
nav ul {
    margin-left: 10px;
}
 
ul#menu li {
    position: relative;
    float: left;
}
 
ul#menu li a {
    display: block;
    float: left;
    width: 150px;
    height: 60px;
    margin: 0;
    background: black url('images/main-bg.png');
    text-indent: -9999px;
}
 
menu form { 
    padding-top: 18px;
    float: left;
    margin-left: 15px;
}
 
menu form a { 
    color: white; 
    text-decoration: none;
}
 
#search {
    background: #3d3f41;
    border: 1px solid #121212;
    height: 20px;
    width: 130px;
}

After adding the CSS we get this look for our menu:

"Ah, OK, I see something now, but it's not good", you might say and you're right. Because we're using sprite image, we also need to specify the default background position for each link individually so every sprite is on it's place. At the end of CSS add the following:

ul#menu li.home a { background-position: -10px top; }
ul#menu li.about a { background-position: -160px top; }
ul#menu li.blog a { background-position: -310px top; }
ul#menu li.videos a { background-position: -460px top; }
ul#menu li.contact a { background-position: -610px top; }

Now, save and reload the page. You should see the menu get a much nicer look, with all the buttons nicely aligned:

Adding the Javascript and making it work

OK, the basic menu layout is done. We'll use jQuery and jQuery Background Position Animations plugin to add the animations to the menu.

NOTE: both jQuery and the plugin are included in the samples.

First, we need to include those scripts in our document:

<script src="js/jquery-1.6.4.min.js" type="text/javascript"></script>
<script src="js/jquery.backgroundPosition.js" type="text/javascript"></script>

Now, let's add mouseover and mouseout event handlers that will run our animations.

$(document).ready(function() {
    $('.main').each(function(i, e) {
         
        var num = i * (-150) + (-10);
         
        $(e)
            .mouseover(function(){
                $(this).stop(true, true).animate({'background-position': num + 'px -60px'})
            })
            .mouseout(function(){
                $(this).stop(true, true).animate({'background-position': num + 'px top'})
            });
    });
});

And the result:

What does this code do? It's simple. We use the jQuery .each() method to execute a function for each element that has a "main" CSS class, namely our links. To every link we add mouseover and mouseout event handler to animate our menu's background-position to the corrent coordinates.

As you can see in the CSS every sprite's X coordinate needs to be 150px from other, but it doesn't start with 0, it starts with -10px, so we use some math to find the correct X-position. We multiply the element's index by 150 and then add 10.

Once we have the correct X-position we know that we need to set Y-position to -60px on mouseover because that's the height of the button. Once the mouse leaves the button, we simply restore the background to original position.

Also, don't forget the .stop() that stops the current animation. Without it we would see animations all the time when the user moves the mouse quickly over the links.

So, our main menu is finished. Now let's add the submenu.

Adding the Submenu

It's easy to add the submenu. We need to add the paragraph with a class submenu and then we'll add CSS and Javascript to make it work. First, the HTML:

<ul id="menu">
<li class="home"><a class="main" href="#">Home</a></li>
<li class="about">
    <a class="main" href="#">About</a>
    <p class="submenu">
        <a href="#">Get to know us</a>
        <a href="#">We, The professionals</a>
        <a href="#">Our Projects</a>
    </p>
</li>
<li class="blog">
    <a class="main" href="#">Blog</a>
    <p class="submenu">
        <a href="#">Networking</a>
        <a href="#">Web Development</a>
        <a href="#">Web Design</a>
    </p>
</li>
<li class="videos"><a class="main" href="#"></a>Videos</li>
<li class="contact"><a class="main" href="#"></a>Contact</li>
</ul>

When you change the HTML like that, our menu will once again be pretty ugly. Now, let's add some CSS to style it:

ul#menu li p.submenu {
    position: absolute;
    top: 60px;
    float: left;
    left: 0;
    margin: 0;
    padding: 0;
    background: none;
    display: none;
    border-left: 1px solid #017500;
    border-right: 1px solid #017500;
}
 
ul#menu li p.submenu a {
    background: #159306 url('images/submenu-bg.png') repeat-x;
    background-position: left top;
    border-bottom: 1px solid #017500;
    color: white;
    width: 180px;
    height: 14px;
    float: left;
    padding: 15px;
    margin-bottom: 0;
    text-decoration: none;
    display: block;
    clear: both;
    text-indent: 0;
}

The key CSS propery here is position: absolute. This way the paragraph, even if displayed doesn't effect the menu.

Now, let's add some life to the submenu. Add this behind the each, but still inside the $(document).ready():

$('.main')
    .mouseover(function () {
        $(this).parent().find('.submenu').slideDown('slow').show();
    });
     
$(".submenu")
    .mouseover(function(){
        $(this).stop(true, true).show();
    });
 
$(".submenu").parent()
    .mouseout(function(){
        $(this).find(".submenu").stop(true, true).slideUp('slow');
    });
 
$(".submenu a")
    .mouseover(function(){
        $(this).stop(true, true).animate({backgroundPosition: '0 -45px'})
    })
    .mouseout(function(){
        $(this).stop(true, true).animate({backgroundPosition: '0 0'})
    });

After adding adding the Javascript, we got this:

It may look complicated, but it's not. First, on mouseover we slide down the submenu and make it visible. Then we say: when the mouse leaves the submenu's parent, hide the submenu (slideUp).

The last part is simple. Same as with the main menu, we animate background-position in the submenu's links, only this time we don't have to do any math, because our image always has the same background-position and is repeated.

Active state

In real-world scenario each of our links would lead on a different page and there we would do some server-side check on which page we are and add the class active to a menu item so our user knows that the menu item corresponds to a page he/she is currently on.

Those classes would be something like this:

ul#menu li.home a.active { background-position: -10px -120px; }
ul#menu li.about a.active { background-position: -160px -120px; }
ul#menu li.blog a.active { background-position: -310px -120px; }
ul#menu li.videos a.active { background-position: -460px -120px; }
ul#menu li.contact a.active { background-position: -610px -120px; }

We won't do that now, but we do need to disable the background animation on the main link if the link has an active class. It's really simple, we'll simply expand our javascriph, so that the first (each) part now goes like this:

$('.main').each(function(i, e) {
             
    var num = i * (-150) + (-10);
     
    $(e)
        .mouseover(function(){
            $(this).not('.active').stop(true, true).animate({'background-position': num + 'px -60px'})
        })
        .mouseout(function(){
            $(this).not('.active').stop(true, true).animate({'background-position': num + 'px top'})
        });
});

Now, let's test that one. Simply manually add a class active to one our menu items, for instance on Videos:

<li class="videos"><a class="main active" href="#"></a></li>

And we're finished with our jQuery & CSS Sprites animated background-position menu.

Also, don't forget to check out these great blogs that have helped and inspired me:

Thanks for visiting. Until next time I wish you all the best!

Comments are closed