One of the more interesting features included in iOS7 is parallax.  The idea of moving elements on the screen in relation to the tilt of the device in order to create the illusion of actual depth.  Some people say this is just useless UI bling but I disagree.  Done in a 'look at me', standout way, sure, anything like this can be just bling.  But done in a subtle, barely noticable way, it can add real value to the interface, allowing your mind to form a stronger physical connection with the device.  In this article I'll discuss how we implemented parallax in the TodoListMe mobile web app including sample javascript.

The Maths

I'll assume you already understand parallax and how it creates the illusion of depth.  The idea being we will shift certain objects on the screen to mimic how they would be perceived if the were physically further back.  For the illusion to work, close enough is not good enough.  Our minds are extremely well developed to understand and process the 3D world we live in.  If we are to fool it then we have to be damn close to real.  I've seen other articles out there implement a simplified model with the argument that it's close enough.  I argue that it is not and if you want something that is actually going to create a believable illusion of depth then keep on reading.  Below is a diagram of the basic model we will be working off.

Parallax Diagram 1

In the diagram above:

  • The black line is the physical screen
  • The blue line is the virtual layer we are simulating depth for
  • P1 is where a point on the virtual layer would be normally (ie without any depth)
  • P2 is the point on the virtual layer
  • P2s is where P2 would appear when projected onto our physical screen.  As you can see,  that point will vary depending on the distance of the eye from the screen.

What we are aiming to work out is how far we need to displace our virtual layer (in both the X and Y axis), in order to simulate the depth.  That is, the distance between P1 and P2s.  I'll first discuss the maths (a simple application of trigonometry) and then offer some sample javascript to implement it.

Let's start with what we know:

  • The depth of the virtual layer ( D ) is something we define.
  • The distance of the viewer from the screen ( F ) is also something we need to set a value for.  (It would be nice if there were a way to know this for certain by way of the camera or something similar but this is unfortunately not possible.)  As you can see in the diagram,  the distance of the viewer from the screen will affect the offset.  You'll have to pick a value that feels roughly right and may need to experiment to find that sweet spot.
  • The rotation of the screen ( a ) we can obtain in degrees from Javascript.

We will refer to the offset (the distance between P1 and P2s) as O.

Let's dive in:

  1. We need to know the angle b .  b = 180 - a  (The full circle above is 360 and we have two 90 degree angles already)
  2. Next is the distance between the eye ( E ) and the virtual point ( P2 ).  L2 = D2 + F2 - 2 D F cos(b)
  3. Now we may proceed to work out the angle c.  We know that L/sin(b) = F/sin(c).  From this c = arcsin((sin(b) / L) * F)
  4. And finally O is derived as O = D tan(c)

Remember you need to do this for both the X and Y axis.

The Javascript

Below is a javascript function that, given arguments D, F and a will calculate the required offset O.

function (angleInDegrees, screenDistance, eyeDistance) {        
       
    // convert angles into radians which javascript function use
    var b = 180 - angleInDegrees;
    var bInRads = b * Math.PI / 180;
       
    var L = Math.sqrt(Math.pow(eyeDistance, 2) + Math.pow(screenDistance, 2) - (2 * eyeDistance * screenDistance * Math.cos(bInRads)));

    var c = Math.asin((Math.sin(bInRads) / L) * screenDistance);
       
    // round to 2 decimal places and return value
    return = Math.round(Math.tan(c) * screenDistance * 100) / 100;
}

Remember, you will need to call this function twice, once to get the X offset and once to get the Y offset.

In order to find the current tilt of your device you will need to listen on the deviceorientation event.  In your code you will have to record the initial tilt of the device and then work out how far you have deviated from that point.

That final Touch

This will give you the correct offsets but to really create the illusion you'll need to go a bit further.

  • Experiment with different values of F until you find a distance that feels right.  This can take a bit of time and can be difficult as it won't feel more right as you get closer to the sweet spot.  It will just feel plain wrong until you hit that sweet spot and all of a sudden it is right.  You may need to experiment with different values of the depth ( D ) as well.  eg on TodoListMe mobile I found that a deeper value for the Categories panel background worked nicely whereas a shallower value looked better for the items on the main page.
  • Add some drop shadow in on items in the foreground.  Keep it subtle though.  Again this has to mimic what would actually happen in real life.  Many people like to put a bold shadow in to make it really stand out.  Remember, if it stands out then it is not what would normally happen and if it's not what would normally happen then it's not helping the illusion.  Again, you'll need to experiment.  When you get it right you won't notice it but the illusion of depth will be enhanced.
  • Use colour to your advantage too.  Items in the distance are usually lighter whilst items in the foreground are usually brighter.

Now go check out the TodoListMe mobile web app to see the end result.