Create a Funky Parallax Background Effect using jQuery

In this tutorial, we’ll be using JQuery to take a horizontally scrolling website and add a parallax scrolling background effect reminiscent of old-school 2D platform games like Sonic the Hedgehog.

Tutorial Details

Last year, the Silverback App site, designed by Carsonified, created some chatter amongst the design community for its clever use of a parallax scrolling effect seen when resizing the browser window.

Like in old 2D platformers like Sonic the Hedgehog, this parallax effect could really come into its own alongside some horizontally scrolling content. This can be easily achieved using a little jQuery magic!

Step 1 – The Skeleton HTML

First, we need to create the basic HTML structure we’ll be using. So fire up your code editor of choice, and create a new HTML file. Within the body tags, enter:

<div id="header">
   		<h1 id="logo">Scrolling Clouds</h1>
    	<ul id="menu">
        	<li><a href="#box1" class="link">Home</a></li>
            <li><a href="#box2" class="link">Box 2</a></li>
            <li><a href="#box3" class="link">Box 3</a></li>
            <li><a href="#box4" class="link">Box 4</a></li>
      </ul>
	</div><!-- end header -->
	<div id="wrapper">
    	<ul id="mask">
        	<li id="box1" class="box">
            	<a name="box1"></a>
                <div class="content"><div class="inner">Home Box</div></div>
            </li><!-- end box1 -->
            <li id="box2" class="box">
            	<a name="box2"></a>
                <div class="content"><div class="inner">Box 2</div></div>
            </li><!-- end box2 -->
            <li id="box3" class="box">
            	<a name="box3"></a>
                <div class="content"><div class="inner">Box 3</div></div>
            </li><!-- end box3 -->
            <li id="box4" class="box">
            	<a name="box4"></a>
                <div class="content"><div class="inner">Box 4</div></div>
            </li><!-- end box4 -->
        </ul><!-- end mask -->
    </div><!-- end wrapper -->

Don’t be too afraid of the extraneous inner divs in the content boxes; I’ll be bending the rules a little here and using those to enable a little CSS3 trickery for a nice border effect.

Step 2 – Some CSS

Create a new CSS file, and for the sake of ease we’ll link to it and the YUI’s reset style sheet in the

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.7.0/build/reset/reset-min.css">
<link rel="stylesheet" type="text/css" href="css/layout.css">
/*** Style Definitions ***/
html				{ background:#67b2ff; font-family:Arial, Helvetica, sans-serif; }
 
/*** Header ***/
h1#logo				{ background:url(../images/Logo.png) top left no-repeat; height:62px; width:481px;
						text-indent:-9999px; position:absolute; top:10px; left:10px; }
 
#menu				{ float:right; position:absolute; top:20px; right:10px; z-index:10; }
 
#menu a				{ background:#FFF; color:#67b2ff; border:#AAA 3px solid;  text-decoration:none; padding:10px;
						margin-right:10px; border-radius:10px; -moz-border-radius:10px; -webkit-border-radius:10px;}
 
#menu a:hover		{ background:#67b2ff; color:#FFF; border:#FFF 3px solid; text-decoration:none; padding:10px;
						margin-right:10px; border-radius:10px; -moz-border-radius:10px; -webkit-border-radius:10px;}
 
#menu li			{ float:left; }
 
/*** Body Content ***/
#wrapper	{ width:100%; height:100%; position:absolute; top:0; left:0; overflow:hidden; }
 
#mask		{ width:400%; height:100%; }
 
.box		{ width:25%; height:100%; float:left; }
 
.content	{ width:960px; height:400px; top:20%; margin: 0 auto; position:relative; background:rgba(255,255,255, 0.3);
				border-radius:35px; -moz-border-radius:35px; -webkit-border-radius:35px; }
 
.inner		{ width:920px; height:360px; background:rgba(255, 255, 255, 0.3); border-radius:30px; -moz-border-radius:30px;
					-webkit-border-radius:30px; margin:5px; padding:15px; top:5px; position:relative; }

Most of this is pretty self-explanatory, but Iíll go over some of the concepts I am using here.
We’ll be scrolling anything within the #wrapper div, so keeping the #header area above that keeps it stationary no matter where we scroll. The #mask div will be the div doing the sliding, so its width is set to 100% * number of boxes it will contain. In this case we need 4 boxes, so the width is 400%.

We want each box to be centred on our screen, so each page is defined by the <li> item .box. We divide 100% (of the width of the parent element) by the number of boxes needed. Thus 100% / 4 = 25%. Finally, the .content div is centred within this element using margin: 0 auto;

Then I added some CSS3 styles in the form of rgba background colours and border-radius. Both of these are supported in every major browser EXCEPT for IE, so this is not recommended for production use. Finally, making the .inner div a slightly smaller clone of the .content div creates a nice translucent border effect.

Now, we have a very lo-fi, but perfectly usable scrolling website to build upon.

Step 3 – Better Living Through JQuery

With our base structure complete and usable without the use of any Javascript, we can get on with the fun part; Progressive Enhancement, or “adding neat stuff for those who can see it”. Weíll be making use of the Jquery library, and a very useful plug-in for it called ScrollTo. So first we need to link to these in the page header, like so:

<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="http://flesler-plugins.googlecode.com/files/jquery.scrollTo-1.4.2-min.js"></script>

Now weíll get those content boxes scrolling. Open a new script tag in the header, and enter the following:

$(document).ready(function() {  
		$('a.link').click(function () {  
			$('#wrapper').scrollTo($(this).attr('href'), 800);
			return false;  
		});  
	});

Simple as that! Let’s step through what the code is doing.

  • Line 1 ensures the entire page is loaded before running the script.
  • Line 2 adds a click listener to all <a> tags with a class of “link”. In this case, that’s all the links in our navigation menu, but we can add this behavior to any link on the page by adding the “link” class to it. We then specify a function to be run when a click is detected.
  • Line3 calls the scrollTo plugin on the #wrapper div, and passes it the destination, and a time in milliseconds in which to complete the animation.
  • Line 4 cancels the browser’s default click behaviour.

So now we know how to scroll the contents of a specific div, we can use that to our advantage. Let’s add a few more divs; two more for each cloud layer. We’ll pop these in just over the header div.

<div id="cloud1" class="clouds">
	<div id="clouds-small"></div>
</div><!-- end clouds -->
<div id="cloud2" class="clouds">
	<div id="clouds-big"></div>
</div><!-- end clouds -->

And style them with some CSS:

/*** Clouds ***/
.clouds		{ width:100%; height:262px; overflow:hidden; }
#clouds-small	{ width:3000px; height:100%; background:url(../images/bg-clouds-small.png) repeat-x;}
#cloud2		{ position:relative; top:-262px; }
#clouds-big	{ width:4000px; height:100%; background:url(../images/bg-clouds-big.png) repeat-x;}

We’ve added dimensions and background images to the divs, made them extra wide to accommodate the scrolling, and positioned them one over the other. All images can be found in the source files, and should be saved in a directory called “images”. We should now have something that looks like the following:

Step 4 – All Together Now!

We’re almost done! Before we can get the scrollTo plugin to move those clouds, we’ll need to write a small helper function that will tell it what point on those divs to move to. There’ll be 4 points we need to set, corresponding to the 4 links.

function setPosition(check, div, p1, p2, p3, p4) {
	if(check==='#box1')
		{
			$(div).scrollTo(p1, 800);
		}
	else if(check==='#box2')
		{
			$(div).scrollTo(p2, 800);
		}
	else if(check==='#box3')
		{
			$(div).scrollTo(p3, 800);
		}
	else
		{
			$(div).scrollTo(p4, 800);
		}
};

So, we’re passing in the content of the link we’re scrolling to, the div we want to move and the 4 positions to move to in the form of e.g: ‘400px’. Back to our click listener function, we’ll add a call to our helper function for our #clouds-small div:

$(document).ready(function() {  
	$('a.link').click(function () {  
		$('#wrapper').scrollTo($(this).attr('href'), 800);
        //add this line
		setPosition($(this).attr('href'), '#cloud1', '0px', '400px', '800px', '1200px')
        //end add this
		return false;  
	});  
});

This will move the small clouds layer by 400px each step. That keeps them slower than the other layers, and helps the illusion that they’re far away. With that in mind, we want the bigger clouds – the closer ones – to move about twice as fast to keep that illusion, so we’ll have them moving 800px per step.

$(document).ready(function() {  
		$('a.link').click(function () {  
		$('#wrapper').scrollTo($(this).attr('href'), 800);
		setPosition($(this).attr('href'), '#cloud1', '0px', '400px', '800px', '1200px')
        //add this line
		setPosition($(this).attr('href'), '#cloud2', '0px', '800px', '1600px', '2400px')
        //end add this
		return false;  
	});  
});

We now have some zippy clouds that follow the content of the page wherever it goes! Let’s just add one final little touch to our page by adding a visual cue so the user can tell what part of the site they’re on. We’ll add a .selected class to our links through our click listener friend, and style it through CSS.

$(document).ready(function() {  
	$('a.link').click(function () {  
		$('#wrapper').scrollTo($(this).attr('href'), 800);
		setPosition($(this).attr('href'), '#cloud1', '0px', '400px', '800px', '1200px')
		setPosition($(this).attr('href'), '#cloud2', '0px', '800px', '1600px', '2400px')
        //add this
		$('a.link').removeClass('selected');  
		$(this).addClass('selected');
        //end add this
		return false;  
	});  
});
#menu a.selected { 
background:#AAA; 
color:#FFF; 
border:#67b2ff 3px solid; 
text-decoration:none; 
padding:10px;
margin-right:10px; 
border-radius:10px;
 -moz-border-radius:10px; 
-webkit-border-radius:10px;
}

And there you have it! These concepts can be used in a myriad of different ways, so play around and see what you come up with.


22

Comments