Beautiful Background Image Navigation with jQuery

In this tutorial we are going to create a beautiful navigation that has a background image slide effect. The main idea is to have three list items that contain the […]

In this tutorial we are going to create a beautiful navigation that has a background image slide effect. The main idea is to have three list items that contain the same background image but with a different position. The background image for each item will be animated to slide into place in different times, creating a really nice effect. The background image sliding direction from the list item in the middle will depend on which item the user was before: coming from the right, it will slide from the left and vice versa.

On top of that we will have sub-menus that appear with their semi-transparent background sliding in. These backgrounds create an awesome effect of actually just being one element that slides into place, changing its color.

Note: There is a new version which let’s you customize things better:
Sliding Background Image Menu with jQuery

We will be using the amazing Background-Position Animation Plugin by Alexander Farkas.

The photos that we will be using are from Pat’s beautiful B&W collection on Flickr.

There will be a little bit of CSS3 involved which absence will almost not be notable when using a browser that does not support its properties (like IE).

We tried to make this one cross-browser compatible and voilà! It works beautifully in Google Chrome, Firefox, Opera, Safari, IE8, IE7 and guess what, it even works respectively in IE6. (We are using an adapted style sheet and you will have to apply some PNG fix if you want the sub-menu backgrounds to be  semi-transparent. )

OK, so let’s get started!

The Markup

The HTML will consist of a wrapper div and an unordered list with three list items. We will initially set some “bg” classes that will have the respective background images. The “menuWrapper” will always have the “bg” class of the current list item so that we have the background image of the current list item.

<div id="menuWrapper" class="menuWrapper bg1">
	<ul class="menu" id="menu">
		<li class="bg1" style="background-position:0 0;">
			<a id="bg1" href="#">Our Passion</a>
			<ul class="sub1" style="background-position:0 0;">
				<li><a href="#">Submenu 1</a></li>
				<li><a href="#">Submenu 2</a></li>
				<li><a href="#">Submenu 3</a></li>
			</ul>
		</li>
		<li class="bg1" style="background-position:-266px 0px;">
			<a id="bg2" href="#">Our Brands</a>
			<ul class="sub2" style="background-position:-266px 0;">
				<li><a href="#">Submenu 1</a></li>
				<li><a href="#">Submenu 2</a></li>
				<li><a href="#">Submenu 3</a></li>
			</ul>
		</li>
		<li class="last bg1" style="background-position:-532px 0px;">
			<a id="bg3" href="#">Contact</a>
			<ul class="sub3" style="background-position:-266px 0;">
				<li><a href="#">Submenu 1</a></li>
				<li><a href="#">Submenu 2</a></li>
				<li><a href="#">Submenu 3</a></li>
			</ul>
		</li>
	</ul>
</div>

For the background animation plugin to work correctly we need to set the position of the background image as inline styles initially. We already set the right position for each background image, for example, the third item will have the background image positioned to the outer right.

As you can see, every list item has another sub-list with three more items. The background image position of these sublists is set to a value that hides the image. When we animate the background then, we will create the effect of sliding it in from the left or the right.

The CSS

Let’s start by the general style of the the “menuWrapper” which will contain the font styles and the size of the whole element:

.menuWrapper{
    font-family: "Trebuchet MS", Arial, sans-serif;;
    font-size: 15px;
    font-style: normal;
    font-weight: normal;
    text-transform:uppercase;
    letter-spacing: normal;
    line-height: 1.45em;
    position:relative;
    margin:20px auto;
    height:542px;
    width:797px;
    background-position:0 0;
    background-repeat:no-repeat;
    background-color:transparent;
}

The list and the list items of the first layer will have the following style:

ul.menu{
    list-style:none;
    width:797px;
}
ul.menu > li{
    float:left;
    width:265px;
    height:542px;
    border-right:1px solid #777;
    background-repeat:no-repeat;
    background-color:transparent;
}
ul.menu > li.last{
    border:none;
}

The selector “>” addresses only the li elements of the first layer and will not be applied to the ones of the sub-menus. We will give the last li the class “last” in order to remove the right border.

The following three classes define the background images. We will give these classes to all the li elements depending on which one we hover. So, if we hover the second li, we will give the “bg2” class to all the first layer list items:

.bg1{
    background-image: url(../images/1.jpg);
}
.bg2{
    background-image: url(../images/2.jpg);
}
.bg3{
    background-image: url(../images/3.jpg);
}

Let’s define the look of the link elements in the first layer list. Since the li elements have a big height, we need to push the link elements down. We do that by setting a high top margin:

ul.menu > li > a{
    float:left;
    width:265px;
    height:50px;
    margin-top:450px;
    text-align:center;
    line-height:50px;
    color:#ddd;
    background-color:#333;
    letter-spacing:1px;
    cursor:pointer;
    text-decoration:none;
    text-shadow:0px 0px 1px #fff;
}

To center the text of a link element vertically, you can give a line-height value equal to the height of the element. (I don’t know why, but when I started with learning CSS, I automatically always used paddings to adapt the height of the element and to center it. Using line-height was a real delight because you can control sizes much better like that.)

The second layer lists would naturally appear after the first layer list, so we use a negative top margin to “pull” them up:

ul.menu > li ul{
    list-style:none;
    float:left;
    margin-top:-180px;
    width:100%;
    height:110px;
    padding-top:20px;
    background-repeat:no-repeat;
    background-color:transparent;
}

The li elements of the sub-menu will be initially hidden. In the script we will fade them in when we hover over their parent list item link:

ul.menu > li ul li{
    display:none;
}

Now we define the classes for the background images of the sub-menus:

ul.menu > li ul.sub1{
    background-image:url(../images/bg1sub.png);
}
ul.menu > li ul.sub2{
    background-image:url(../images/bg2sub.png);
}
ul.menu > li ul.sub3{
    background-image:url(../images/bg3sub.png);
}

The link elements of the li elements will have the following style:

ul.menu > li ul li a{
    color:#fff;
    text-decoration:none;
    line-height:30px;
    margin-left:20px;
    text-shadow:1px 1px 1px #444;
    font-size:11px;
}

ul.menu > li ul li a:hover{
    border-bottom:1px dotted #fff;
}

The first sub-list will be shown in the beginning:

ul.menu > li ul.sub1 li{
    display:block;
}

And that’s all the style. Take a look at the ZIP file for the IE6 style sheet.
Now let’s take a look at the JavaScript.

The JavaScript

What we do in the script is the following: we first check where we are coming from and then we animate the background positions of the list elements in the first level and the backgrounds of the sub-menus accordingly:

$(function() {
	/* position of the <li> that is currently shown */
	var current = 0;

	$('#bg1,#bg2,#bg3').mouseover(function(e){

		var $this = $(this);
		/* if we hover the current one, then don't do anything */
		if($this.parent().index() == current)
			return;

		/* item is bg1 or bg2 or bg3, depending where we are hovering */
		var item = e.target.id;

		/*
		this is the sub menu overlay. Let's hide the current one
		if we hover the first <li> or if we come from the last one,
		then the overlay should move left -> right,
		otherwise right->left
		 */
		if(item == 'bg1' || current == 2)
			$('#menu .sub'+parseInt(current+1))
			    .stop()
				.animate({backgroundPosition:"(-266px 0)"},300,function(){
					$(this).find('li').hide();
				});
		else
			$('#menu .sub'+parseInt(current+1))
				.stop()
				.animate({backgroundPosition:"(266px 0)"},300,function(){
					$(this).find('li').hide();
				});

		if(item == 'bg1' || current == 2){
			/*
			if we hover the first <li> or if we come from
			the last one, then the images should move left -> right
			*/
			$('#menu > li')
				.animate({backgroundPosition:"(-800px 0)"},0)
				.removeClass('bg1 bg2 bg3')
				.addClass(item);
			move(1,item);
		}
		else{
			/*
			if we hover the first <li> or if we come
			from the last one, then the images should move
			right -> left
			*/
			$('#menu > li')
				.animate({backgroundPosition:"(800px 0)"},0)
				.removeClass('bg1 bg2 bg3')
				.addClass(item);
			move(0,item);
		}

		/*
		We want that if we go from the first one to the last one
		(without hovering the middle one), or from the last one
		to the first one, the middle menu's overlay should also
		slide, either from left to right or right to left.
		 */
		if(current == 2 && item == 'bg1'){
			$('#menu .sub'+parseInt(current))
			.stop()
			.animate({backgroundPosition:"(-266px 0)"},300);
		}
		if(current == 0 && item == 'bg3'){
			$('#menu .sub'+parseInt(current+2))
			.stop()
			.animate({backgroundPosition:"(266px 0)"},300);
		}

		/* change the current element */
		current = $this.parent().index();

		/* let's make the overlay of the current one appear */

		$('#menu .sub'+parseInt(current+1))
			.stop().animate({backgroundPosition:"(0 0)"},300,function(){
				$(this).find('li').fadeIn();
			});
	});
	/*
	dir:1 - move left->right
	dir:0 - move right->left
	 */
	function move(dir,item){
		if(dir){
			$('#bg1').parent()
					 .stop()
					 .animate({backgroundPosition:"(0 0)"},200);
			$('#bg2').parent()
					 .stop()
					 .animate({backgroundPosition:"(-266px 0)"},300);
			$('#bg3').parent()
					 .stop()
					 .animate({backgroundPosition:"(-532px 0)"},400,function(){
						$('#menuWrapper').removeClass('bg1 bg2 bg3')
										 .addClass(item);
					 });
		}
		else{
			$('#bg1').parent()
					 .stop()
					 .animate({backgroundPosition:"(0 0)"},400,function(){
						$('#menuWrapper').removeClass('bg1 bg2 bg3')
										 .addClass(item);
					 });
			$('#bg2').parent()
					 .stop()
					 .animate({backgroundPosition:"(-266px 0)"},300);
			$('#bg3').parent()
					 .stop()
					 .animate({backgroundPosition:"(-532px 0)"},200);
		}
	}
});

And that’s it! A beautiful cross-browser capable effect!
I hope that you enjoyed the tutorial.

Message from TestkingIf want to learn professional web designing but have no time to attent regular class then testking a+ is best solution though. Download the testking mcse design tutorials and testking VCP-410 study guide to learn how to create beautiful and unique logo designs.

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 335

Comments are closed.
  1. This is one of the most beautiful and unique examples I’ve seen on this website. Really like the effect, well done!

  2. Wow that is awesome. Wish you would put a demo link at the top. I like to get to the climax first.

    • Thank you all for your great feedback!

      @James, you can also click on the post image, that will always lead you to the demo 🙂 and hopefully to a great climax! Cheers, ML 😉

  3. Very nice effect.

    It seems that Flash is about to become useless since jQuery can achieve those kind of effects now.

  4. Bravo! I laughed, I cried…it’s a tour de force. I just found your site this week…straight to the top shelf.

    I agree with James about the demo being linked higher–gives me motivation to read the nitty-gritty. But the clue about using the post image; good to know.

    Maybe Steve Jobs was right…

  5. This is a very nice tutorial with such an impressive effect.

    Thank you Mary!

  6. One of the best effects I’ve seen in a long time – vell done!

  7. Amazing example! jQuery is hot as always. One question: can I make lines between parts of images invisible?

    • @Devaka, of course, just do the following: remove the border-right from “ul.menu > li” in the CSS and set the width of “.menuWrapper” and “ul.menu” to 795px. Actually it looks pretty cool like that 🙂 Thanks for your feedback! Cheers, ML

  8. Absolutely beautiful. And if I wanted a different or random menu to appear first when the page opens….? I’m trying to figure that part myself but…

  9. Wow! Really nice and smooth. Haven’t seen a solution like this before.

  10. Hum amazing code but auwful Arial Narrow font. Please change that 😡

  11. Thanks so much Mary Lou. I’m sure I’ll be able to do what I’d like now!

  12. this is very nice. Just found ur website and I think will visit frequently .

  13. If gotten this working fine with 3 images and even different dimensions, but would really like *4* images – and – start with a different image by default (before any action).

    I’ve gotten the four images to work, but having some difficulty with login on hiding the submenus.

  14. great tutorial, I try to do a identical copy and run perfect, so the smooth slide on each background is better on your sample vs my copy. Why?
    url: http://www.mastercafe.com/ejemplos/bgnavi.html
    All run perfect, so check the smooth lateral movement. Same PC, same FireFox, same task, better your sample, can’t understand why.

  15. I have successfully modified this script to accommodate 4 images (or more), including changes in logic and dimensions.

    You can download the archive here:
    BeautifulBackgroundImageNavigation_X.zip

    “index4.html” and “style4.css” are the modified files. I did not take the time to create a modified “styleIE6.css” for IE6.

    From here, it is quite manageable to deduce the necessary changes in js logic, css and dimensions to accommodate a limitless combination of images, submenus and dimensions. Just keep in mind that “4,” in my 4-column model, relates to the total number of images (columns).

    In return for this contribution, can anyone show the way to present a “default” menuWrapper image when there is no “hover” over any of the menu items or parents? (I see that I am not the first to wish for this!)

  16. Absolutely gorgeous effect !
    Great Job, and thanks for sharing !!

    Would it be hard to setup this effect as a ‘slideshow’ without the menu’s, but with autoplay looping through a range of images ?

    Cheers,
    Arve

  17. This is a really really nice script. Thank you so much. It’s very easy to implement as well!

  18. Congratulations!! wonderful way of handling menus, realy original.

    @R.bird removing the initial menus themselves is easy find this in the css
    ul.menu > li ul.sub1 li{
    display:block;
    } and kill the display: block (or the whole entry)

    That leaves the transparent overlay though and try as I might I can’t find where that’s coming from or how to stop it.

    Any help gratefully received!

  19. Wow very impressive and unique tutorial. Very creative, I love it.

    Now I just need to find a use for it 🙂
    Would be very good for a splash page. Anyone have any ideas how else it can be intergrated into an existing site?

  20. Well done, thank you so much! Playing around with the code, I can’t seem to figure out how to effectively add or subtract a panel. Say I only want 2 panels, how would I get this result? Thanks again!

  21. Simply marvelous.. exactly like flash animation but file size would be much smaller than that. Great work. Thanks for sharing with us.

  22. I love this feature! I will most certainly be using it in one of my next designs.

  23. @R.bird = I had to say thank you so much for your tweak info = I’ve tried to figure out a solution to your request and I think I am almost there, but not yet = ie: the initial static image to show up on initial display. I know the solution resides somewhere with creating an additional .bgx css to the menu ones. Anyways I have my home page menu showing up with 8 different sections now at 1040px wide by 611 high. Wow! thank you so much Mary Lou for making this JQuery available = JQuery versus Flash versus iPad = I think Adobe has something to worry about and that HTML5 combined with jQuery will rule web development at least for the next couple of weeks!

  24. I tried to implement the above in my blogger blog. But its not working. I have hosted all the pics and javascript and modified the links accordingly. Used the html/javascript page element for the html code, pasted the jquery in head tags and css above b skin tags. But its not working. can some one help? Just for info i hav successfully copy pasted scripts from flowplayer.org and everything works.
    Some be kind to give me a solutio to implement in blogger.

    • @Ratnakar I really wish I could help you but I never did something in blogger. What exactly shows when you integrate it? Did you try to view the source of the page after integration? Cheers, ML

  25. Thx for the prompt reply ML, heres the link to my blog
    http://spicemyblog.blogspot.com
    The CSS works but the Jquery doesnt seem to work. U get a static image of the first loaded one.
    If u could provide a solution it would be wonderful. Thx in advance.

    • @Ratnakar I think I found the problem! Can you try to add another }); at the end of the script? It was throwing me an error on Firebug that there would be brackets missing, so maybe it was just that! I hope it works, cheers, ML

  26. @mary lou is there any way to have it so that when the page loads *no* menu block is displayed? So they only appear once the user hovers over the menu block title at the bottom.
    I’ve tried to find a way to do it but without succes 🙁