The Parallax Header: How I Do It

December 04, 2009

This morning I was asked by Tyrun on Twitter (sorry, I couldn’t find your actual name, sir) about something that I’ve been asked a few times: I LOVE your header background, how on earth did you do that?

The very short answer is: with JavaScript and CSS.

Of course, that’s not a very satisfying response, so I’ll go ahead and expound a bit more. I did it in three steps. First, creating the right group of images. Secondly, with some simple CSS and HTML. Lastly, with a surprisingly short JS script.

Step 1: The Images

The first step for parallax scrolling, in any application, is having multiple layers of images to scroll at different speeds, with each layer representing another part of the passing landscape. In the case of this site, I’ve got four: clouds, mountains, hills, and forest. By themselves, neither layer looks terribly interesting.

Layer 1: Clouds

clouds

Layer 2: Mountains

mountains

Layer 3: Hills

hills

Layer 4: Forest

forest

They’ll have to be stacked over each other, so in order to be seen through one another they need to have transparency. This is why I used PNGs (although depending on the type of art you use, GIFs are fine).

Step 2: The CSS and HTML

Next, the images will have to be stacked over each other. I made four empty divs which I put in the header/branding div as follows:

<div id="cloudLayer" > </div>
<div id="mountainLayer" > </div>
<div id="hillLayer" > </div>
<div id="forestLayer"> </div>

Although I’m not normally a fan of non-semantic divs, for this special effect I need something to hang the imagery upon. These four divs will be what we need for the CSS:

div#cloudLayer, div#mountainLayer, div#hillLayer, div#forestLayer {
 height:200px;
 position:absolute;
 text-indent:-9999em;
 width:100%;
}

div#cloudLayer {
background:transparent url(images/clouds.png) repeat-x scroll left top;
opacity:0.6;
}

div#mountainLayer {
background:transparent url(images/mountains.png) repeat-x scroll left top;
}

div#hillLayer {
background:transparent url(images/hills.png) repeat-x scroll left top;
}

div#forestLayer {
background:transparent url(images/forest.png) repeat-x scroll left top;
}

So each div is set at the same height, as wide as the parent element (the header), and absolutely positioned so they all overlap. Each background image is set appropriately to repeat horizontally along the layer it is within. If nothing further was done, this would be a complicated way to create a repeating landscape background. Only one small bit is left to make it scroll.

Step 3: The JavaScript (with jQuery!)

I love jQuery. It’s a convenient, compact JS library that makes cross-browser coding easy and compact. You could probably do this script without it, but by necessity it’d be a lot larger. Here’s the part of my script that controls the scrolling:

$('#branding').mousemove(function(e) {
mouseX = e.clientX;
$('#cloudLayer').css('background-position', Math.floor(mouseX / 4) + 'px 0');
$('#mountainLayer').css('background-position', Math.floor(mouseX / 3) + 'px 0');
$('#hillLayer').css('background-position', Math.floor(mouseX / 2) + 'px 0');
$('#forestLayer').css('background-position', mouseX + 'px 0');
});

I want the scrolling to only occur when the mouse is over the header, which is a div I call branding. So I’ve bound the .mousemove() event handling function to that div. I get the x-coordinate of the mouse when that even fires (anytime the mouse moves) and then adjust the background image positioning on the layer divs accordingly.

If I moved each layer’s background image by the same amount, the image would scroll all at once, and there’d be no parallax effect. Therefore, I instead divide the x-coordinate by a different amount for three of the four layers, moving each background image an increasingly smaller amount for the “far” layers.

The finished result is visible in the header above!

As always, if you have any comments or questions, feel free to share.

15 Responses to “The Parallax Header: How I Do It”

  1. Thanks for the explanation Kyle! I recognized the same effect as the Silverback (http://silverbackapp.com/) resize – but I was still curious how you achieved yours, and how much more yours was interactive (following the mouse, instead of only changing upon resizing).

    Great article – thanks again!

    -Tyrun

  2. There is also a pretty awesome jQuery plugin called jparallax – http://webdev.stephband.info/parallax.html which supports up/down movement too. The first demo is pretty good too – http://webdev.stephband.info/parallax_demos.html

  3. I’m pretty new to html, css, standards, etc. You indirectly said that the html or css wasn’t semantic and I was wondering why that was. My guess is because you used div’s for each image, as you said something to hang them on. Is this true? Thanks for helping my education and for showing us this setup!

  4. @Kevin – You nailed it. The divs don’t serve any content-related purpose, rather they’re just extra spots for the presentation of the background images to be affixed. In my view, semantic markup is always content-oriented, with the presentation coming from CSS.

    I’m sure views on that topic vary in severity, though.

  5. I think the importance of a truly semantic website depends on the website purpose. Don’t use this effect if semantics and function over form is important.

    But thanks Kyle for the tut!

  6. Div and span elements exist to group things without implying semantics. This is exactly the right use for them if semantics is important. @Jack, the semantic Web doesn’t require you to avoid things that are fun, non-textual, or just useless.

  7. @Michael – I know they’re semantic get-out-of-jail-free cards. It doesn’t mean that filling my header up with them feels right. Too hard wired, I think. ;)

  8. wow, this amazing tricks, i like this

  9. [...] CSSquirrel: The Parallax Header: How I Do It [...]

  10. I’d say that, ideally, only semantic content should go in the HTML file. Why not create all those divs with jQuery?

  11. @VeoSotano – That’s a valid solution. As Jack reminded us in the thread, though, divs have no semantic meaning. So even though they’re excessive (in that they don’t hold any content), they wouldn’t qualify (to me) as non-semantic.

    All that said, the reason I chose not to insert the divs via JavaScript is that I wanted the landscape to exist if JavaScript was disabled.

  12. @Kyle This brings up a question that I have since a long time ago… How many browsers which are CSS- and image-capable, but don’t do JavaScript? I know users can manually disable JS in their browsers, but my guess is those are very rare… with so many pages out there that rely on it, no normal user would do that. I guess there are those who are security obsessed, but that raises another question – how insecure is JavaScript? Is there really any danger for your computer if you leave it on?

  13. It seems to me that the header moves the wrong way – I would think having the motion of the background oppose the mouse movement would seem more natural.

  14. I’m working on a series of “Javascript Feelings” which attempt to explain complex human emotions using Javascript. I’ve used the parallax effect in my first piece entitled “Intimacy With Strangers.”

    http://verytogether.com/lifestyle/play/javascript-feelings-intimacy-with-strangers.html

  15. Do you have a packaged version of this available?