Create a Parallax Website Using jQuery

Jan 02 2015 Extras, Tutorials

Parallax websites are pretty sweet. Want to learn how it’s done?

Final Product – What We Will Create:

view parallax demo

Source Files – What You Need To Create It:

download source files

We’ll Need a Few Plugins…

Stellar.js
A plugin by Mark Dalgleish that provides parallax effects to any scrolling element. We’ll use this plugin to drive the parallax effects we are looking for.

Waypoints.js
A plugin by Caleb Troughton that will allow us to execute a function when a user scrolls to specific elements on the page. We’ll use this one to change the title font and color as the user scrolls from section to section.

jQuery Easing
An easing plugin by GSGD for our scrolling animation.

HTML – Head

On to our code – we’ll start with the standard HTML5 declaration and a link to our stylesheet (parallax.css). Next we’ll call in our JavaScript files, starting with a link to a hosted version of the the latest jQuery release. We’ll follow that with links to our plugins and then call our initialization file (parallax.init.js) last.

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Parallax Demo</title>
        <meta charset="utf-8">
        
        <!-- viewport responsive settings -->
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
        
        <!-- favicon -->
        <link rel="icon" type="image/png" href="https://www.digitaltap.tv/favicon.ico"/>
        
        <!-- CSS -->
        <link rel="stylesheet" type="text/css" href="css/parallax.css">
        
        <!-- JavaScript -->
        <script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
        <script type="text/javascript" src="js/jquery.stellar.min.js"></script>
        <script type="text/javascript" src="js/waypoints.min.js"></script>
        <script type="text/javascript" src="js/jquery.easing.1.3.js"></script>
        <script type="text/javascript" src="js/parallax.init.js"></script>
    </head>
  • Tip: Be sure to call jQuery first and the initialization file last.

HTML – Body

On to the body of our HTML markup. We’ll start off with the “Scroll Down” heading wrapped in an h1 tag – later we will use JavaScript to change the look and text content in response to our vertical scroll position. The content has been divided into four sections – as the user scrolls through each section, we’ll use Waypoints.js to detect their position and change or control elements in response. Next we will need to scroll elements and background images at different speeds in order to create the parallax effect. To do this, we’ll use Stellar.js to control the velocity of various elements, which we define using ratios. A ratio of “1.0” would be normal speed – values less than “1.0” will scroll slower, while ratios above “1.0” will scroll faster.

<body>
    
        <!-- Title -->
        <h1 data-stellar-ratio="0">Scroll Down</h1>   
         
        <!-- Sections -->
        <div class="section" id="section1" data-section="1" data-stellar-background-ratio="0.5">
            <div data-stellar-ratio="0.1" data-stellar-vertical-offset="-250" id="anchor1"><img src="images/anchor.svg"></div>
            <div data-stellar-ratio="1.8" data-stellar-vertical-offset="-850" id="anchor2"><img src="images/anchor.svg"></div>
            <div data-stellar-ratio="0.9" data-stellar-vertical-offset="-230" id="anchor3"><img src="images/anchor.svg"></div>
            <div data-stellar-ratio="2.9" data-stellar-vertical-offset="-280" id="anchor4"><img src="images/anchor.svg"></div>
            <div data-stellar-ratio="0.2" data-stellar-vertical-offset="-200" id="anchor5"><img src="images/anchor.svg"></div>
            <a class="btn arrow animated bounce" data-section="2"></a> <!-- Arrow Button -->
        </div>
        
        <div class="section" id="section2" data-section="2" data-stellar-background-ratio="0.5">
            <div data-stellar-ratio="0.1" data-stellar-vertical-offset="-250" id="paw1"><img src="images/paw.svg"></div>
            <div data-stellar-ratio="1.8" data-stellar-vertical-offset="-850" id="paw2"><img src="images/paw.svg"></div>
            <div data-stellar-ratio="0.9" data-stellar-vertical-offset="-230" id="paw3"><img src="images/paw.svg"></div>
            <div data-stellar-ratio="2.9" data-stellar-vertical-offset="-280" id="paw4"><img src="images/paw.svg"></div>
            <div data-stellar-ratio="0.2" data-stellar-vertical-offset="-200" id="paw5"><img src="images/paw.svg"></div>
            <a class="btn arrow animated bounce" data-section="3"></a> <!-- Arrow Button -->
        </div>
        
        <div class="section" id="section3" data-section="3" data-stellar-background-ratio="0.5">
            <div data-stellar-ratio="0.1" data-stellar-vertical-offset="-250" id="shuttle1"><img src="images/shuttle.svg"></div>
            <div data-stellar-ratio="1.8" data-stellar-vertical-offset="-850" id="shuttle2"><img src="images/shuttle.svg"></div>
            <div data-stellar-ratio="0.9" data-stellar-vertical-offset="-230" id="shuttle3"><img src="images/shuttle.svg"></div>
            <div data-stellar-ratio="2.9" data-stellar-vertical-offset="-280" id="shuttle4"><img src="images/shuttle.svg"></div>
            <div data-stellar-ratio="0.2" data-stellar-vertical-offset="-200" id="shuttle5"><img src="images/shuttle.svg"></div>
            <a class="btn arrow animated bounce" data-section="4"></a> <!-- Arrow Button -->
        </div>
        
        <div class="section" id="section4" data-section="4" data-stellar-background-ratio="0.5">
            <div data-stellar-ratio="0.1" data-stellar-vertical-offset="-250" id="ufo1"><img src="images/ufo.svg"></div>
            <div data-stellar-ratio="1.8" data-stellar-vertical-offset="-850" id="ufo2"><img src="images/ufo.svg"></div>
            <div data-stellar-ratio="0.9" data-stellar-vertical-offset="-230" id="ufo3"><img src="images/ufo.svg"></div>
            <div data-stellar-ratio="2.9" data-stellar-vertical-offset="-280" id="ufo4"><img src="images/ufo.svg"></div>
            <div data-stellar-ratio="0.2" data-stellar-vertical-offset="-200" id="ufo5"><img src="images/ufo.svg"></div>
            <a class="btn last arrow" data-section="1"></a> <!-- Arrow Button -->
        </div>

  • Tip: Adjust the background image scroll speed by changing the value of “data-stellar-background-ratio”. To change the scroll speed of the icons, edit the value of “data-stellar-vertical-offset”.

Lastly, we’ll load the Google Fonts we are using in the design with a bit of JavaScript.

     
        <script type="text/javascript"> // initialize Google fonts used for the titles
            WebFontConfig = {
                google: { families: [ 'Seaweed+Script::latin', 'Open+Sans:400,300,700,700italic,400italic,300italic:latin', 'Chicle::latin', 'Arbutus::latin', 'Audiowide::latin', 'Codystar::latin' ] }
            };
            (function() {
                var wf = document.createElement('script');
                wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
                  '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
                wf.type = 'text/javascript';
                wf.async = 'true';
                var s = document.getElementsByTagName('script')[0];
                s.parentNode.insertBefore(wf, s);
            })();
        </script>
        
    </body>
</html>
  • Tip: We are using quite a few fonts here for tutorial purposes – try to keep the number of your font choices to a minimum in order to save on page loading time.

CSS – Main Styles and Headings

Now lets begin to look at the CSS for the site – we’ll start by setting the html and body to a height/width of 100% – we’ll also apply a few default styles. Next we’ll begin styling our “h1” headings for each section – you’ll notice that a different typeface has been applied to each section, as well as various other styles such as color, case, size, etc. For the first “h1”, we are going to define a fixed position, located at 50% from the top and left sides of the window. We’ll also want to add negative margins in order to manually center the title, and a z-index to keep it on top of the other elements.

* {
    margin: 0;
    padding: 0;
}

html, body {
    width: 100%;
    height: 100%;
    background-color: #333;
}

body {
    text-shadow:none;
    font-family: 'Open Sans', sans-serif;
}

h1 {
    color: rgba(69,179,156,0.50);
    font-size: 84px;
    position: fixed;
    top: 50%;
    left: 50%;
    margin-left: -235px;
    margin-top: -59px;
    z-index: 1;
}

h1.section1title {
    font-family: 'Seaweed Script', cursive;
}

h1.section2title {
    color: rgba(86, 70, 43, 0.35);
    font-family: 'Arbutus', cursive;
    text-transform:uppercase;
    font-size:64px;
}

h1.section3title {
    color: rgba(79, 86, 102, 0.45);
    font-family: 'Audiowide', cursive;
    text-transform:uppercase;
    font-size:64px;
}

h1.section4title {
    color: rgba(98, 97, 95, 1.0);
    font-family: 'Codystar', cursive;
    text-transform:uppercase;
    font-size:76px;
    letter-spacing: 30px;
}
  • Tip: Define your colors in RGB using the “rgba(r,g,b,alpha)” declaration (where alpha refers to the desired opacity from 0.0 to 1.0) instead of hex values to add transparency to your object or text.

CSS – Arrow Button

Now lets add a bouncing directional arrow to guide our viewer and entice them to scroll downward. First we’ll stick the button to the bottom of the page and style it, then we’ll add some CSS3 transformations and keyframes for our animated elements (for more information on this, check out Chris Coyier’s great tutorial on CSS3 animation). We’ll also add a class of “.last” to the final arrow button and flip it 180° to let the user know they have reached the bottom of the page.

/* Down/Up Arrow Button */

.btn {
    display:block;
    width:50px;
    height:50px;
    position:absolute;
    bottom:0px;
    left:50%;
    margin-left: -25px;
    background-color: transparent;
    background-image:url(../images/arrow.svg);
    background-repeat:no-repeat;
    background-position: center center;  
    -webkit-transition-duration: 0.7s;
    transition-duration: 0.7s;
    -moz-opacity:0.5;
    -webkit-opacity:0.5;
    opacity:0.5;
}

.btn:hover {
    background-color: rgba(255,255,255,0.6);
    cursor:pointer;
    -webkit-transition-duration: 0.7s;
    transition-duration: 0.7s;
}

.btn.last {
    -ms-transform:rotate(180deg); 
    -webkit-transform:rotate(180deg);
    transform:rotate(180deg); 
    background-color: #000;
}


/* Bouncing Arrow Animation */

@-webkit-keyframes bounce { 

	0%, 20%, 50%, 80%, 100% {
		-webkit-transform: translateY(0);
		transform: translateY(0);
	}
	
	40% {
		-webkit-transform: translateY(-30px);
		transform: translateY(-30px);
	}
	
	60% {
		-webkit-transform: translateY(-15px);
		transform: translateY(-15px);
	}
	
}

@keyframes bounce {
	
	0%, 20%, 50%, 80%, 100% {
		-moz-transform: translateY(0);
		-ms-transform: translateY(0);
		-webkit-transform: translateY(0);
		transform: translateY(0);
	}
	
	40% {
		-moz-transform: translateY(-30px);
		-ms-transform: translateY(-30px);
		-webkit-transform: translateY(-30px);
		transform: translateY(-30px);
	}
	
	60% {
		-moz-transform: translateY(-15px);
		-ms-transform: translateY(-15px);
		-webkit-transform: translateY(-15px);
		transform: translateY(-15px);
	}
	
}

.bounce {
    -moz-animation: bounce 2s infinite;
    -webkit-animation: bounce 2s infinite;
    animation: bounce 2s infinite;
}
  • Tip: When using vendor specific prefixes (ie. -moz, -webkit, etc.), it’s good practice to specify the prefixed version first and then the non-prefixed version.

CSS – Sections and Images

And now our sections – we’ll start with a few styles to keep our content contained within their respective sections, then add our four background images. Then we’ll add some styles to set the position and opacity of our “floating” icons.

/* Sections */

.section {
    width:100%;
    height:100%;
    position: relative;
    overflow:hidden;
    background-attachment:scroll;
}

#section1 {
    background-image:url(../images/lighthouse.jpg);
    background-size:cover;
}

#section2 {
    background-image:url(../images/wowser.jpg);
    background-size:cover;
}

#section3 {
    background-image:url(../images/shuttle.jpg);
    background-size:cover;
}

#section4 {
    background-image:url(../images/moon.jpg);
    background-size:cover;
}

/* Floating Images */

.section img {
    width:100%;
    height:auto;
    -moz-opacity:0.2;
    -webkit-opacity:0.2;
    opacity:0.2;
}

#section3 img {
    width:100%;
    height:auto;
    -moz-opacity:0.5;
    -webkit-opacity:0.5;
    opacity:0.5;
}

#section4 img {
    width:100%;
    height:auto;
    -moz-opacity:1.0;
    -webkit-opacity:1.0;
    opacity:1.0;
}

#anchor1, #paw1, #shuttle1, #ufo1 {
    width: 200px;
    height: 200px;
    position: absolute;
    top: 300px;
    left: 50px;
}

#anchor2, #paw2, #shuttle2, #ufo2 {
    width: 100px;
    height: 100px;
    position: absolute;
    top: 80px;
    right: 460px;
}

#anchor3, #paw3, #shuttle3, #ufo3 {
    width: 150px;
    height: 150px;
    position: absolute;
    top: 30px;
    right: 200px;
}

#anchor4, #paw4, #shuttle4, #ufo4 {
    width: 60px;
    height: 60px;
    position: absolute;
    top: 100px;
    left: 500px;
}

#anchor5, #paw5, #shuttle5, #ufo5 {
    width: 80px;
    height: 80px;
    position: absolute;
    top: 300px;
    left: 600px;
}

#shuttle1, #shuttle5 { /* rotate two shuttles 180 degrees */
    -moz-transform: rotate(180deg);
    -ms-transform: rotate(180deg);
    -o-transform: rotate(180deg);
    -webkit-transform: rotate(180deg);
    transform: rotate(180deg);
}
  • Tip: Rotate two of the shuttle icons so they don’t look like they are going backwards… or falling to earth!

CSS – Media Query

Finally, add a few media queries to make the site display properly on smaller viewports.

/* Media Query (added for smaller viewports) */
@media only screen and (max-width: 480px) { 
	
	h1 {
	    font-size: 53px;
	    margin-left: -125px;
	}
	
	h1.section2title {
	    font-size: 54px;
	}
	
	h1.section3title {
	    font-size: 50px;
	}
	
	h1.section4title {
	    font-size: 34px;
	    letter-spacing: 20px;
	}
	
	#anchor1, #paw1, #shuttle1, #ufo1 {
	    display:none !important;
	}

}
  • Tip: These media queries are only an example of how to address smaller viewports – you may want to experiment further in order to ensure the best possible user experience across devices.

JavaScript – Start

Next, let’s dive into some JavaScript – we’ll start things off by defining our variables and initializing Stellar.js.

	
	// define vars below
	section = $('.section');
	btn = $('.btn');
	htmlbody = $('html,body');
	
	$(window).stellar(); // initialize stellar.js

JavaScript – Waypoints

Moving along, we’ll start writing our functions for detecting the scroll direction of the user, adding/removing classes and changing text content based on their waypoint. We will also define our offset (how far from the top of the window the callback should fire) and also set our function to trigger every time a user crosses our waypoint. I have added comments to the code in an attempt to make it easier to dissect.

	$('#section1').waypoint(function(event, direction) { // "direction" returns scrolling direction of the user
		if (direction === 'down') { // if the user is scrolling down...
			$('h1').addClass( 'section1title' ).text("Scroll Down"); // add class, change text
		}
		else { 
			$('h1').addClass( 'section1title' ).text("Scroll Down"); // add class, change text
		}
	},
	{
		offset: '100%', // how far from the top of the window the callback should fire - 100% because it is the cover section
		triggerOnce: false // trigger every time user crosses the waypoint - if true, the waypoint will destroy itself after its first trigger
	});

	$('#section2').waypoint(function(event, direction) { // "direction" return scrolling direction of the user
		if (direction === 'down') { // if the user is scrolling down...
			$('h1').addClass( 'section2title' ).removeClass( 'section1title' ).text("Keep Going"); // add class, remove previous class, change text
		}
		else { 
			$('h1').addClass( 'section1title' ).removeClass( 'section2title' ).text("Scroll Down"); // add class, remove previous class, change text
		}
	},
	{
		offset: '50%', // how far from the top of the window the callback should fire
		triggerOnce: false // trigger every time user crosses the waypoint - if true, the waypoint will destroy itself after its first trigger
	});

	$('#section3').waypoint(function(event, direction) { // "direction" returns scrolling direction of the user
		if (direction === 'down') { // if the user is scrolling down... 
			$('h1').addClass( 'section3title' ).removeClass( 'section2title' ).text("Almost There"); // add class, remove previous class, change text
		}
		else { 
			$('h1').addClass( 'section2title' ).removeClass( 'section3title' ).text("Keep Going"); // add class, remove previous class, change text
		}
	},
	{
		offset: '50%', // how far from the top of the window the callback should fire
		triggerOnce: false // trigger every time user crosses the waypoint - if true, the waypoint will destroy itself after its first trigger
	});
	
	$('#section4').waypoint(function(event, direction) { // "direction" returns scrolling direction of the user
		if (direction === 'down') { // if the user is scrolling down... 
			$('h1').addClass( 'section4title' ).removeClass( 'section3title' ).text("Landed"); // add class, remove previous class, change text
		}
		else { 
			$('h1').addClass( 'section3title' ).removeClass( 'section4title' ).text("Almost There"); // add class, remove previous class, change text
		}
	},
	{
		offset: '50%', // how far from the top of the window the callback should fire
		triggerOnce: false // trigger every time user crosses the waypoint - if true, the waypoint will destroy itself after its first trigger
	});
  • Tip: We use a conditional statement in case the user is scrolling up.

JavaScript – Arrow Button

Our last bit of JavaScript controls our arrow button, directing it to scroll to the next consecutive section (with easing!).

// scroll to section via the bouncing arrow
	function goToByScroll(datasection) {
		htmlbody.animate({ // scroll the body...
			scrollTop: $('.section[data-section="' + datasection + '"]').offset().top // ...then scroll to the next section...
		}, 2000, 'easeInOutExpo'); // ...with easing.
	}
	
	// bouncing arrow scroll button
	btn.click(function (e) { // when the button is clicked...
		e.preventDefault(); // default action of the event will not be triggered
		datasection = $(this).attr('data-section'); // set var to attr
		goToByScroll(datasection); // scroll to section
	});

Source Files

view parallax demo

download source files