Pixel Acres

Build a parallax scrolling website interface with jQuery and CSS

Parallax scrolling website interfaces have been popping up all over the place recently. I didn’t want to miss out on the fun, so I have put together a parallax scrolling demo built using jQuery and CSS.

Parallax scrolling interface

Parallax what?

Even if you’re not familiar with the term “parallax scrolling” you will certainly be familiar with the technique. Parallax scrolling is a 2d animation process that creates an illusion of depth by animating foreground layers faster than background layers. When you observe the landscape from a moving car, objects closer to the car appear to pass you faster than scenery further away. Parallax scrolling uses the same principle to trick the viewer into thinking they are observing a 3d scene.

Demo and Download

My demo web page shows one approach to building a vertical parallax scrolling interface:

View demo
Download source

You can scroll in the usual fashion, use the navigation menu at the right-hand side of the page, or the next/prev buttons that appear underneath each article. As you scroll, the page’s four content layers are animated independently of one another to create an illusion of depth.

The scrolling looks smoothest in Safari (at least that’s the case on my PC), but my demo should work in any modern browser.

Disclaimer 1: Because this is just an experiment I’ve not spent any time optimising the demo to work on mobile devices. I wanted to keep the demo lean ‘n’ mean, and not clutter it by sniffing mobile browsers and forking my code. On a production site you’d want to ensure that the site degrades gracefully on mobile devices, where scroll events and fixed positioning might work in unexpected ways.

Disclaimer 2: The navigation menu in my demo is inspired by the menu on the Nike Better World website. If you plan on implementing a similar menu on a production site, please be aware of its origin.

How it works

The articles and background layers are given a fixed positioned with CSS, and assigned a z-index so that the foreground layers appear above the background layers. The four layers are: small clouds, large clouds, balloon/landscape images, articles.

/* foreground (ballons/landscape) */
#parallax-bg3 {
    z-index: 3;
    position: fixed;
    left: 50%; /* align left edge with center of viewport */
    top: 0;
    width: 940px;
    margin-left: -470px; /* move left by half element's width */
}

Within each layer individual content elements are absolutely positioned. This was the most fiddly part of the process, since the elements need to positioned in such a way that they align in a pleasing manner when the user scrolls to any of the four articles. In this case it was really just a process of trial and error.

#bg3-1 {
    position: absolute;
    top: -111px;
    left: 355px;
}
#bg3-2 {
    position: absolute;
    top: 812px;
    left: 321px;
}
/* etc... */

A few lines of jQuery control the parallax effect, triggered by a scroll event. I was surprised how easy this was to achieve, it is literally just a handful of lines of code.

$(window).bind('scroll',function(e){
    parallaxScroll();
});
 
function parallaxScroll(){
    var scrolled = $(window).scrollTop();
    $('#parallax-bg1').css('top',(0-(scrolled*.25))+'px');
    $('#parallax-bg2').css('top',(0-(scrolled*.5))+'px');
    $('#parallax-bg3').css('top',(0-(scrolled*.75))+'px');
}

As you can see the CSS top property is used to move each layer as the user scrolls. The foreground layer is always aligned to the top of the document, while the movement of other layers is adjusted according to their depth. The lower a layer sits in the stack, the less distance it is moved.

The rest of the jQuery is concerned with controlling the navigation menus. When the user clicks a navigation button the page scrolls to the top of the associated article. In the event that the user has JavaScript disabled, regular HTML anchor links still allow the page to be navigated, but without any fancy pants animations.

Next steps

I’m sure there are plenty of other approaches to parallax scrolling, and hopefully my experiment provides a starting point for your own explorations of the technique.

Update

I have updated the demo so that each parallax layer is given a fixed, rather than absolute, position. This approach gives a smoother scrolling effect.

158 Responses to “Build a parallax scrolling website interface with jQuery and CSS”

  1. Kiltro says:

    I’ve been a good time enjoying this experiment, thank you very much.

    How can i add one more button with its own content and animation?

  2. Jonathan says:

    @Kiltro You would do that by adding another <article> to the #content div, giving it a unique id (e.g. id=”new-article”), and styling it according to your requirements with CSS.

    Then add another navigation button to the #primary menu, with its href pointing at your article (e.g. href=”#new-article”).

    And finally, add a jQuery click handler for the new nav button. It should be fairly clear from looking at parallax.js how to do that.

  3. Kiltro says:

    Yes, I did that … I had some problems at the beginning and use a single very high background image.. and buttons do not work properly, reducing the size of the background picture, the problem disappeared.

  4. 101ers says:

    Hey – Great plug-in. How does this hold up in IE?

    Any suggestions on repositioning the ‘right-fixed nav’ to be positioned fixed at the top?

    cheers.

  5. Jonathan says:

    @101ers My demo works in IE7+. Maybe IE6 too, but I’ve not checked. To make the nav fixed to the top of the viewport, just change its CSS top and right properties, e.g. top: 0; right: 50%

  6. 101ers says:

    Awesome man.

    It’s working great – weird thing though, after I customized the menu; the ‘smooth animated scroll’ became somewhat shaky/laggy.

    P.S. I know you said you hadn’t optimized for any mobile devices, but did see you were using some HTML5 in the markup, do you know if it has any functionality on mobile? I was thinking about trying to optimize it, or at worst degrade similar to as you were talking about in the tut.

    Thanks dude

  7. Jonathan says:

    @101ers My demo actually works fairly acceptably on iOS devices. Scrolling between sections works, but the position of background layers is only updated after the scroll has finished. So you don’t get a parallax effect, but the page isn’t broken.

  8. 101ers says:

    Awesome – any suggestions on the easiest way to add additional scroll points that animate the same as the first four?

  9. Jonathan says:

    @101ers Sorry, you’re on your own there! But the steps involved are:

    - Add another article to the HTML markup and style it.
    - Add any additional background images to the #parallax-bg3, #parallax-bg2 and #parallax-bg1, and position them with CSS.
    - Add an additional button to the navigation menu.
    - Add a click handler for your new button to parallax.js.
    - Modify the logic of the redrawDotNav function in parallax.js to include your new article.

    There may be something I have overlooked, but that’s the gist of it.

  10. Marcus says:

    I noticed that on your demo (and my working file) that on firefox if you scroll by dragging the scroll tab, the window shudders. Only on Firefox.

  11. Jonathan says:

    @Marcus – I think that may just be the nature of Firefox. I’ve noticed the same thing on other parallax scrolling sites, e.g. http://www.manufacturedessai.it/it/ I assume there is a small delay before a JS scroll event is triggered.

  12. Nik says:

    Hi,

    I want to use the above parallax, but in horizontal manner. User can use keyboard arrows, mouse wheel to navigate to next slide, also corresponding navigation dots must be selected.

    I have seen many examples no one did horizontal scroll with navi dots.

    what changes should I make in your example to make it horizontal

    Thanks,
    Nik

  13. I tried the demo on chrome, and I found that when I scroll with the mouse wheel, it slightly jumps. That is because the frame is rendered in it’s new position before the scroll event is triggered.

    I was thinking that a possible solution might be to use fixed position instead of absolute (and fixing all the math accordingly), this would keep the layers in place until the event is called. This though would break the demo entirely on browsers that don’t support fixed positioning, including iOS safari prior to version 5.

    But still, great post, it’s nice to see someone putting up a tutorial on this recently popular technique.

  14. Davit says:

    Testing it in Chrome and experience is jaggy, I think it happens for elements that are meant to scroll slower then the page. When I was working on similar project and used http://www.nikebetterworld.com/ as a source and inspiration, I’ve stumbled upon the same problem. Nike website surprisingly doesn’t have such problem. One thing that they do differently, as far as I investigated, they do not move separate elements, but backgrounds. I’m planning to address this in my next parallax project.

  15. Denes says:

    Wow,
    great inspiration.
    Check this dynamic 3D cloudy sky parallax webpage: http://bit.ly/vWDYlK

  16. Nelson says:

    Has anybody had success in the meantime fixing the graphic glitches in other browser than Safari? I tried everything and it always does that.

  17. Razan says:

    Great job..dude
    keep it up.

  18. Jonathan says:

    Just an update on the flickering issue some of you have mentioned. I have been able to fix this by changing the positioning of #parallax-bg1, #parallax-bg2 and #parallax-bg3 from relative to fixed, then changing the parallaxScroll JS function to:

    function parallaxScroll(){
    var scrolled = $(window).scrollTop();
    $(‘#parallax-bg1′).css(‘top’,(0-(scrolled*.25))+’px’);
    $(‘#parallax-bg2′).css(‘top’,(0-(scrolled*.5))+’px’);
    $(‘#parallax-bg3′).css(‘top’,(0-(scrolled*.75))+’px’);
    }

    Need to test this a bit more, but assuming I don’t notice any issues I’ll update the demo with these code revisions.

    In the meantime, you can download my revised source files here: f6design.com/projects/parallax-scrolling/parallax-scrolling-demo-fixed-pos.zip

  19. David says:

    Thanks for fix! Safari was always smooth but this has fixed the jitter on Chrome.

  20. Nelson says:

    In case you want to use the background-positioning method instead of positioning the elements themselves, there’s a similar fix for that as well. Just change the css of the elements affected to have a background-attachment: fixed. tested it out in Firefox and Chrome, with no more glitching as well (cause it also happened as in the elements positioning way)

  21. MARK says:

    Thanks a million. Great, super straighforward overview. I’m SOOO not a programer but was able to get this customized and working. Learned a lot.

    Thanks man!

  22. Mathieu says:

    Thanks a lot, great article!!

    Is it possible to use the keys down & up to scroll a section to another?

    Still thanks

  23. Kevin says:

    Thank..
    So great.
    I’ve been having trouble with holding the navigation button when it’s on its page.
    And just found this awesome demo and source.
    If I am right, the last section of “parallax.js” is about it.. isn’t it?
    Thank you.. this is so helpful!!
    peace!

  24. Jonathan says:

    @Kevin That’s right, the function redrawDotNav is bound to the window scroll event, measures how far the page has scrolled, and styles the nav button for the current ‘page’ accordingly.

  25. Jonathan says:

    Just an update regarding the flickering issue. I have updated the demo, download zip, and source code examples on this page with the fixed version.

  26. Nate says:

    Hi Jonathan…

    I was wondering if you could please help me integrate keyboard navigation for this script. My goal is to configure the up/down arrows to navigate between each section or circle. Any help is much appreciated.

    Thank You and happy 2012.

  27. Darko Martic says:

    What exactly we could/should do to optimize this simple code for mobile devices? I’m interested in iOS devices, so it is a Mobile Safari in mind…

    As someone already mentioned – on iPad I can see only “jump” of clouds after scroll finishes, so was wondering is there anything to do to make this finger-real-time more friendly?

    Thanx

  28. Teresa says:

    Hi did anyone figure out how to integrate keyboard navigation?? Would be awesome.

  29. Awesome advice on how to use jQuery and CSS to design parallax scrolling features. B Culture Media wrote about the visual enhancement parallax scrolling gives a website here at http://bculture.tumblr.com/post/16986692131/parallax-scrolling

  30. Justin Jones says:

    Hi!

    Is there any way to replace the buttons with normal text buttons, so you dont have to rollover to see the text.

    Thanks,
    and very nice work!!

    Regards,

    Justin

  31. Allan White says:

    Built a parallax-scrolling microsite based on your demo. It’s working pretty well – I just wanted to say thanks!

    Out of all the parallax tutorials out there, I found your markup and logically-constructed CSS, HTML and JS to be the simplest and most elegant. Very nice. I even tweaked the JS to move elements in other directions, yielding some neat effects.

    I’ll share this tutorial, and thanks again!

  32. Jonathan says:

    @Allan Your feedback is much appreciated. I’m pleased you found my demo useful!

  33. Laetitia says:

    Hi,

    I want to use this parallax, butin horizontal. I tried it at horizontal but it didn’t work. What changes should I make in your example to make it horizontal.

    Thanks.

  34. Nelson says:

    You should change every instance of ScrollTop to ScrollLeft, y values per x values and make sure you can get all elements in an horizontal scroll across the page. Usually through floating them all until the last of them, after which you insert a span or div with the style of clear:both, to make the browser calculate the full width of all of the window.

    I didn’t do it trough this plugin, but rather hard coded most of the code and based off some of it elsewhere, but I got an working page here (that has not my copyright though, I advert you, but the studio where I made it has it, so it is not open source, but as with everything web, you are free to see its entrails and understand its workarounds.

    Here it is — http://sayheyny.com/wordpress Please pay attention, cause this is a commercial website, with some awareness already on the web. Again, beware when copying code, cause I cannot be responsible for it. Cheers!

  35. Helen says:

    Brilliantly clear article. Also the replies to the comments have been really helpful. I’ve been reading a few articles on parallax scrolling recently and this has helped pull it all together. Thanks.

  36. Hi Jonathan,
    Just want to say thanks for providing this. I just launched http://pixel-fable.com based on the code you provided.

    For those who are interested, I made some modifications to the CSS and HTML that allows this to work responsively. Basically, I moved all the images to background images and set breakpoints with media queries, so I could serve smaller images and realign the divs for smaller screens. It’s not perfect, but that is the beauty of design, I guess!

    Cheers!

    Senongo

  37. Mirko says:

    Hi Jonathan,

    Thanks for great piece of code. I think it works great when scrolling with buttons, but i think that there isn’t that sense of parallax when scrolling with the mouse.

    This is only complaint i can find, everything else is top notch.Also i would like to ask what is the licence with these ballon images, i find them quite nice:)

  38. Tom says:

    Great example of parallax scrolling and thanks for posting the source!

  39. manuel says:

    Hi, how i can positioned a fixed background image?

  40. Absolutely awesome and easily understandable. Thanks a bunch!

  41. Antonio says:

    Hello!)
    Your solution is only applicable to sites with a fixed height. But if content on the page will be changed dynamically? For example, in cases with CMS.
    Thank you!

  42. Jonathan says:

    @Antonio. That’s right, my solution is intended for a specific use-case, in which the designer/developer has control over the amount of content that is to be displayed, and therefore is able to construct a highly customised scrolling experience.

  43. Manuel says:

    @Jonathan. how i can positioned a fixed background image? Thanks so much!

  44. Jonathan says:

    @Manuel I’m not really sure how to answer that except to say “look at my HTML and CSS”. My demo uses a mix of fixed positioning for each of the three background layers (bg clouds, midground clouds, balloons), and absolute positioning for individual elements (e.g. an individual cloud or balloon). If you have a good grasp of CSS it ought to be simple enough to follow.

  45. manuel says:

    @Jonathan. Yeah i saw. But i can’t put a fixed (do no scroll) background image instead a gray color. do u undesrtand? sorru for my english

  46. Jonathan says:

    @Manuel

    body {
    background: #000 url(your_image.png) top center fixed no-repeat;
    }

  47. manuel says:

    @Jonathan. Yes, i tryed this. if you testing dont work.

  48. Jonathan says:

    @Manuel I did test, and it worked for me in Chrome.

  49. manuel says:

    @Jonathan. Ok. maybe i have an another problem. i will check. Thanks for your time

  50. Motiejus says:

    I really like this example as a starting point, thank you.
    Working with it further I found a more convenient solution for redrawDotNav() func. You could easily implement Bootstrap’s scrollSpy plugin, so you don’t need to hardcode section elements
    Cheers!

Leave a Reply