Pseudo-3D Parallax Image Effect with JavaScript, CSS, and jQuery

About a month ago while browsing Hacker News I stumbled across an interesting link and discussion about a pure CSS parallax image effect created by Roman Cortes.

On Hacker News the item led to a discussion about how the effect should have been done in JavaScript, rather than the pure CSS approach taken by Roman Cortes.  Basically in the original version Cortes laid out the image and then added transparent spans which when hovered over changed the relative positions of the layer images.

I was interested in the effect at the time so I bookmarked in my "things to try out later" folder.  Yesterday, I finally got around to this project again, and I decided to create a similar effect except using JavaScript rather than pure CSS.  As my website already includes jQuery I used it as the CSS transformation engine.  The result is below.  Move your mouse over the image to change the perspective and move the layers.  (If you are viewing this post via a feed reader or a news aggregator it probably won't work.  You will have to view the original post.)

The Maids of Honour (Las Meninas) by Diego Veláquez

Probably the biggest advantage to using JavaScript is that I was able to make the animation smoother and also include vertical movement.  According to Cortes' explanation his solution uses 80 vertical elements to modify the CSS.  I can't imagine the laborious process that must have gone into creating those 80 elements.  It is little wonder then that Cortes made the image move only in the horizontal direction, as adding vertical movement support would have increased the number of element and the number of CSS modifiers needed to 6400, which would have been completely unreasonable.

In the end I found the JavaScript jQuery solution to be very quick and easy to implement.  The hardest part, the modifying of the original painting to cut out the figures and repair the background areas, had already been done by Cortes.

All I had to do was add a few lines of beginning CSS and a simple jQuery event handler.  The complete code is below, along with the original images.

The Code

<?xml version="1.0" encoding="utf-8"?>
    <title>Pseudo 3D / Parallax Effect</title>
    <style type='text/css'>
        overflow: hidden;
        position: relative;
        width: 429px;
        height: 435px;
        border: 10px solid black;
        background: url(background.jpg) no-repeat scroll -100px -20px;
        width: 352px;
        height: 435px;
        position: absolute;
        width: 148px;
        height: 455px;
        top: -20px;
        left: 282px;
        position: absolute;
        background: url(sprites.png) no-repeat scroll -426px -40px;
        left: -10px;
        top: 35px;
        width: 91px;
        height: 400px;
        position: absolute;
        background: url(sprites.png) no-repeat scroll -71px -75px;
        top: 210px;
        left: 262px;
        width: 90px;
        height: 91px;
        position: absolute;
        background: url(sprites.png) no-repeat scroll -54px -215px;
        top: 203px;
        left: 62px;
        width: 348px;
        height: 218px;
        position: absolute;
        background: url(sprites.png) no-repeat scroll -647px -285px;;
        top: 280px;
        left: 212px;
        width: 224px;
        height: 167px;
        position: absolute;
    <script type='text/javascript' src='jquery-1.3.2.min.js'></script>
    <script type='text/javascript'> 
      var verticalAdjuster = .30;
      var backgroundSpeed = .15;
      var wallSpeed = .15;
      var womenSpeed = .1;
      var childrenSpeed = .05;
      var dogSpeed = .03;
      var easelSpeed = .02;
      jQuery(document).ready( function(){      
        $("#painting").mousemove( function(e){
          var x = 429 - (e.pageX - this.offsetLeft);
          var y = 435 - (e.pageY - this.offsetTop);
          $("#background").css("background-position", (backgroundSpeed*x-100) + " " + (backgroundSpeed*verticalAdjuster*y-20));
          $("#wall").css("top", (wallSpeed*verticalAdjuster*y-20) + "px");
          $("#wall").css("left", (wallSpeed*x+282) + "px");
          $("#wall").css("width", (148-wallSpeed*x) + "px");
          $("#twoWomen").css("top", (210+womenSpeed*verticalAdjuster*y) + "px");
          $("#twoWomen").css("left", (262+womenSpeed*x) + "px");
          $("#childGroup").css("top", (203+childrenSpeed*verticalAdjuster*y) + "px");
          $("#childGroup").css("left", (52+childrenSpeed*x) + "px");
          $("#boyAndDog").css("top", (280+dogSpeed*verticalAdjuster*y) + "px");
          $("#boyAndDog").css("left", (212+dogSpeed*x) + "px");
          $("#easel").css("top", (35+easelSpeed*verticalAdjuster*y) + "px");
          $("#easel").css("left", (-10+easelSpeed*x) + "px");
     <div id='painting'>
       <div id='background'></div>
       <img id='wall' src='wall.jpg' />
       <div id='twoWomen'></div>
       <div id='childGroup'></div>
       <div id='easel'></div>
       <div id='boyAndDog'></div>
    <p style='font: 12px Arial;'>The Maids of Honour (Las Meninas) by Diego Vel√°zquez</p>

Original Images

The background and wall images:

The sprite sheet:


  1. Too cool. Love it.

  2. it can be done better in flash, but then again, so can everything.

  3. Very true. Still I have a feeling that this plain HTML and JavaScript version probably loads faster than a flash object would.

  4. As for me I never had seen anything alike. This is just wonderful. Thank you for the awakening to the dreams.
    Now I know too little about Javascript or the alike languages and their codes, yet your article inspired me to start my "things to try out later" folder too.
    At a moment Art by Tomas looks traditionally, yet you inspired me to think about the addition of physical move to my pictures.

  5. Looking for parallax effects I came to this place. Learning from what I saw here I made this website:

    Its not finished yet, but you can see I've used it to the end.

    I wasn't finished with just repositioning images and altering widhts. I wanted to use skew effects to give the walls an improved feeling of depth. It wasn't easy at first but now I am very satisfied with the result, thanks to you basically.

    When finished i'll let props to experimentgarden on source code. Thank you.

  6. Nice! I like this effect very much. Maybe I will try it someday on my website.

  7. which is the best effected site of java and javascripting ?
    i want to learn giving animation effects to the words.