Recreating the Firewatch Parallax Effect

As a web designer you probably cry inside when you hear the word “parallax.” It’s tainted. Dirty. An overused (and quite often improperly used) term that has come to mean “gratuitous scrolling effects” or worse; the complete hijacking of your browser’s scrollbar.

And in almost all cases, you would be right to feel that way.

But amidst the turmoil, there are, in my opinion, a few gems that get it right. And one of those is the website for Firewatch.

Firewatch is the brainchild of Campo Santo, in partnership with Panic, and it looks gorgeous. But not only does the game have an amazing look & feel, but the site, as well, has the best use of parallax scrolling I have seen this year. Go ahead, check it out.

The lovely parallax effect on firewatchgame.com — it’s really much nicer live.

There are a few reasons this effect is so nice.

  1. It doesn't hijack the scrollbar. Update: Actually, turns out it does, sort of, I just didn’t notice it on Chrome for Mac.
  2. It’s simple.
  3. The art is just beautiful.

Okay, let’s try it out

I’m going to walk you through the steps of re-creating this effect with some simple HTML, CSS, and JavaScript.

A small note before we begin. I’m not an artist of talent anywhere near the caliber of whoever made the Firewatch illustrations, so my work will be more simplistic in nature. As mentioned earlier, the beautiful art is really what ties this all together. That said I am happy with the result, and I hope you take the opportunity to practice your own art skills with me!

If you can’t wait to see it, then check out my end result here.


The design

Before we even start coding, we need to create our design. If you looked at the end result, then you'll see that I've chosen to play on the theme of Firewatch, and do something a little different with Ice and cool blues.

In whatever program you prefer, create each layer of your illustration and save it as a transparent PNG. Make it wide. I set mine at 1920px in width, and if possible make it something that can be tiled horizontally.

If you plan on supporting Retina displays (@2x resolution) then make the images twice as big, and we’ll scale with CSS later.

For reference, here are my layers:
Layer 1 (logo), Layer 2, Layer 3, Layer 4, Layer 5, Layer 6.

Here’s what my layers look like, all together.

HTML

We will start with a simple template as our base.

Create an index.html file in your favorite text editor, and paste in the following code.

View the HTML: https://gist.github.com/hamstu/57726ec39d110931f548

Notice how we have created a .parallax-layer div for each layer of our illustration, and that they all follow the same pattern.

<div class='parallax-container'>
<div class='parallax-layer layer-0' data-[...]></div>
[...]
</div>

In a moment we will use CSS to add the background-image to each of these layers. Also important are the data- attributes, these will be used in our JavaScript to control the parallax effects. Lower values will move the item slower (so it appears farther away). This is the core principle of the parallax effect.

If you have more or less layers, be sure to add and remove the .parallax-layer divs accordingly, and make sure that layers in the background have lower speed values.

The data-max-scroll attribute is used to stop the layers from scrolling past a specified point. This is important to prevent them from scrolling too much and breaking the effect. You can tweak it later, so don't worry about it too much now.

CSS

The CSS is a little more complex, but still fairly straightforward.

Create a new file called style.css in the same directory as your HTML, and paste in the following CSS.

View the CSS: https://gist.github.com/hamstu/8ba1122b442b367e640e

Let’s break it down now.

Each layer has a lot in common, so we start with a .parallax-layer class (line 12) which sets up some standard styles. You'll notice we give each parallax layer a height of 500px. This height value should be at least as much as the height of your layer graphics, but it could be more. The background images as you can see are attached to the bottom of this div. In my example the net effect is that 500px pushes everything down and makes room for the logo layer to show. Later on you can play with this value and you'll see what I mean.

You'll also notice that .parallax-layer sets position to fixed (line 15). This is very important. Fixed position elements don’t move with the rest of the page content when you scroll. With position: fixed; we can move the layers manually when the user scrolls, and at our own speed, thus creating the lovely parallax effect. We'll detail how to do this in the JavaScript section later on.

One last thing to note about the .parallax-layer is that we're setting a background-size property. This CSS property allows you to specify the width x height of your layer graphic, and since mine are all the same I can just set it once here. I'm actually setting this value to half the actual width and height so that the graphics still looks clear on Retina displays. If you are using your own graphics, you will need to change the background-size width x height to match your images.

For every layer in your design, you'll also need an associated .layer-X class. This class sets up the proper z-index, background-image, and spacing (with the top property) that are specific to that layer.

.layer-2 {
z-index: 5;
background-image: url('...');
top: -50px;
}

You'll need to play around here with the values, the top value in particular, to arrange the layers how you want them to first appear. Be sure you setup the z-index’s correctly too, in ascending value for each layer.

You should be able to preview the page as you write the CSS and tweak things as you go.

You’ll notice that I made some special adjustments to .layer-0. This is my logo layer and since it wasn't wide like the other layers I had to tweak the background-size property and it’s position to get it placed correctly.

Last of all, a note on colors and blending. Your top-most layer (in my case, .layer-5) is going to need to blend/bleed into the content. If you look at the CSS you'll see that I've set a background color on my .content that matches the color of my top-most layer’s graphic. I also set this color as my body’s background-color, just in case. This should prevent any unseemly gaps.

JavaScript

If you did everything right you should have your layers properly stacked and looking nice, but not yet scrolling in any way.

Now create a new file called parallax.js in the same directory as your index.html, and style.css. Paste in the following code.

View the JavaScript: https://gist.github.com/hamstu/925c6fac166c431fe607

I won't go through this code line by line, but in a nutshell it sets up two objects. The first is a ParallaxPart, and the second is a ParallaxManager. At the end of the file you create a new instance of ParallaxManager and pass in the classname of your parallax elements, which in our case is .parallax-layer.

new ParallaxManager('.parallax-layer');

The ParallaxManager object loops through each .parallax-layer and creates a ParallaxPart to represent it. Then whenever the user scrolls, the ParallaxManager sends a message to each Part telling it to update it’s poisiton based on the scroll amount.

If all is well, then adding this code should be the final touch needed to make your parallax effect work!

See my final demo here.

Two things you may want to change.

  1. The data-parallax-speed attributes in the HTML. To adjust the parallax speed on each layer.
  2. The data-max-scroll attribute. This attribute tells the JavaScript when to stop parallaxing the elements, the value I have on all my layers is 565; meaning once you scroll to 565px or greater the effect stops. You’ll want to play with this number to find what works best for your design. If you don’t want the parallaxing to stop at all, set this number to something very large (like 9999).

Other paths

There are, as always, many ways to achieve the same thing. Perhaps one of these would better suit your needs.

  1. Sam Beckham has recreated the Firewatch effect with CSS (Sass) only! Using a combination of a Sass for-loop, 3d transform and scale properties. Very cool.
  2. You could use a fancy-shmancy JavaScript library like Skrollr or Stellar to do the heavy lifting for you.
  3. Also of note; HTML5Rocks wrote an article on parallax effects that even talks about using a <canvas> element to do the work, very interesting!

So long, and thanks for all the scrolling

Hopefully this tutorial has been helpful to you. I certainly learned a lot putting it together. Till next time!

Want to know when I write more tutorials?
Click here to sign up, and I’ll let you know.