The information expressed in this article is my opinion. The ideas, concepts, and examples below may not be the optimal solution. Not only are the ideas my opinion, but my method is one in an infinte set of possiblities, especially in a language like JavaScript. This guide is meant to be just that: a guide.
Parallax scrolling is a technique in which scale, and motion are used to create an illusion of depth. The background stars below are an example of this technique. In this tutorial we will be examining the BgStar class used in the example below.
Scale plays a major role in parallax scrolling. The farther an object is from the observer, the smaller the object appears from their perspective. This will be the first attribute that we examine from the example. We will begin by creating a constructor class for BgStar
function BgStar( x, y ){
// coordinates
this.x = x;
this.y = y;
// parallax
this.z = randomFloat( .05, 1.5 );
this.scale = 2 - this.z;
}
There are a few important items in this snippet. First is that in these snippets there will be functions used that are not native JavaScript, like randomFloat. For the purpose of this tutorial it is not important how these various functions work. All we need to know is in this case randomFloat will return a number between 0.05 and 1.5.
Also the variable this.z is not used as a traditional z index. In this example z is a measure of how far an object is away from the screen. High values of z correspond to a smaller image scale, which means that the width and height of the image to be drawn will be smaller. Low values of z correspond to larger image scales, making objects appear closer to the screen.
Now this is where all of the magic happens. Using the same value as the last section, we move the object based on the a page's y offset. Finding a way to check the page's y offset cross-browser was more difficult than I had anticipated. This is the solution that I discovered from kennebec on StackOverflow:
function getScrollHeight(){
if(typeof pageYOffset!= 'undefined'){
//most browsers except IE before #9
return pageYOffset;
}
else{
var body = document.body, //IE 'quirks'
docElement = document.documentElement; //IE with doctype
docElement = (docElement.clientHeight) ? docElement : body;
return docElement.scrollTop;
}
}
Now using this function we can add two variables to the constructor, as well as a function to the BgStar's prototype.
function BgStar( x, y ){
// coordinates
this.x = x;
this.y = y;
// parallax
this.z = randomFloat( .05, 1.5 );
this.scale = 2 - this.z;
this.originalScrollHeight = getScrollHeight();
this.parallaxOffset = 0;
}
BgStar.prototype = new (function(){
this.draw = someDrawFunction; // will be used in another section
this.parallaxScrolling = function(){
// in this example brackets are important for order of operations
this.parallaxOffset = ( this.originalScrollHeight - getScrollHeight() ) / this.z;
};
})(); // sorry if there are any dog ball haters.
// it is worth noting that this code may be written many different ways
In this algorithm we take the documents current offset relative to its offset when this instance was created:
( this.originalScrollHeight - getScrollHeight() )
And divide it by its simulated distance, this.z. Therefore objects that are farther away (larger values), will move less than objets that are closer (smaller values).
The main reason why this.z is used in this manner, is the reduce the amount of math required in this step. The numbers used are completely arbitrary, I used trial and error to find numbers that suited the needs of my application. Most cases will not require such a pronounced degree of motion (up to 20:1 ratio of offset to scroll).
So far we have discussed how to calculate the parallax offset of objects, but we have not yet applied this algorithm to create anything of value. Now there are many different ways that this can be done, but one that I am a fan uses jQuery. By adding an event listener to the window obeject.
window.addEventListener( 'scroll', function(){
arrayOfBgStars.forEach( function( bgStar ){
bgStar.parallaxScrolling();
bgStar.draw();
});
});
Not only have we spotted a mythical double callback, but we have also saved a lot of resources with this method as opposed to an iterative method. Instead of calling parallaxScorlling, x frames per second, we only have to call this function when the screen has been scrolled. I also added a draw function just as an example of how the object is finally drawn, however this may not be realistic depending on how it is used.