Parallax UI for PhoneGap and Mobile Web Apps

By Andrew Trice

Device motion and accelerometer programming interfaces have been around for years now, but up until iOS 7 we saw minimal use of them on most mobile devices. Sure there was a “level” app, or some gimmicky games, but not much to be seen for widespread use. iOS 6 started to introduce user interface elements that changed with the orientation of the device, but iOS 7 has really taken device motion in the user interface to the next level starting with the parallax motion of the phone’s home screen. On the iOS 7 home screen you will notice that the icons and background shift as you rotate the device, offering the illusion of depth between the background and the foreground elements. Parallax motion is the movement of visual objects at different rates to introduce the illusion of depth – generally objects farther away move at slower rates, giving them the appearance of being further away.

In this post, I’ll demonstrate three samples for introducing parallax motion and depth in the user interface for PhoneGap or mobile web applications, all implemented completely with HTML, CSS, and JavaScript.

Note: These samples are designed for a phone form factor only – I have not implemented them as responsive or adaptive designs. I’ve also experienced the best performance on iOS devices, but these techniques also work with Android. I have not tested these on other platforms.

Examples In Action

Have a look at the video below to see the three examples in action, and afterwards we can look at how these effects were implemented. The three samples you will see are:

  1. A simple icon screen with parallax motion
  2. An icon screen with multiple layers of parallax motion
  3. An interactive app scenario with parallax motion and a scrolling background – don’t miss this one, it is my favorite!

My intent with these samples was to create a user interface that has device motion/parallax interaction similar to those introduced with iOS 7’s home screen. The basis of all of these examples is that when you rotate the device, elements in the foreground move towards the angle of rotation, and elements in the background move opposite the angle of rotation. The greater the angle of rotation, the greater the movement/shifting of the UI elements.

This movement gives the illusion that the foreground and background elements are rotating around a center point, and that they are not on the same plane of depth, thus adding to the richness and immersive feeling of the application’s experience.


In JavaScript you can use device motion events to access information from the device’s accelerometer. In PhoneGap applications, you can also use the Accelerometer class, but I went with the JavaScript events so that these examples can be easily viewed in a mobile device browser without PhoneGap.

A Simple Icon Screen with Parallax Motion

Let’s examine the first example. The basic HTML structure is extremely simple. We have a div which contains buttons and a footer element.

    <div class="content">
        <button><img src="assets/airplane.png" /></button>
        <button><img src="assets/crosshair.png" /></button>
        <button><img src="assets/currency.png" /></button>
        <button><img src="assets/leaf.png" /></button>
    <div class="footer">
        All images copyright 2013 <a href="" target="_blank">Andrew Trice</a>. 

The parallax motion is implemented by using a translate3d CSS transform on the “content” div to animate the foreground elements. The background image is actually a CSS background for the <body> element. The background animation is implemented by shifting the CSS background position for this image so that it appears to move.

One thing to keep in mind for both of these animation techniques is that there is minimal impact on browser reflow operations – this is intentional to keep runtime performance at optimal levels.

The JavaScript used to implement the parallax motion is also fairly simple, as you will see below. The JavaScript uses an event listener for the window.ondeviceorientation event and adjusts CSS styles based upon the event’s gamma and beta values – these values represent the number of degrees of rotation of the device.

You’ll also notice that the CSS is being applied in a render loop using window.requestAnimationFrame. This is so that any changes are applied inline with the browser’s rendering cycle for optimal performance. Note: This is using the requestAnimationFrame shim from Paul Irish for cross platform support – requestAnimationFrame is not supported on older Android platforms.

var bodyCSS = "0px 0px";
var backgroundCSS = "0px 0px";
var contentCSS = "translate3d( 0,0,0 );";

window.ondeviceorientation = function(event) {
    gamma = event.gamma/90;
    beta = event.beta/180;
    var temp = 0;

    //handle actual device orientation relative to the user interface
    switch (window.orientation) {
        case 90: 
            temp = gamma;
            gamma = beta;
            beta = temp;
        case -90: 
            temp = -gamma;
            gamma = beta;
            beta = temp;

    var increment = 15;
    var xPosition = -100 - (gamma * increment);
    var yPosition = -100 - (beta * increment)*2;

    bodyCSS = xPosition + "px " + yPosition + "px";
    backgroundCSS = "translate3d( " + (xPosition) + "px, " + (yPosition) + "px, " + " 0px)";

    var xPosition = -(gamma * increment);
    var yPosition = -(beta * increment);
    contentCSS = "translate3d( " + (-xPosition) + "px, " + (-yPosition) + "px, " + " 0px)";

    //for debugging only
    //$(".content").html( "A:" + event.alpha + "
B:" + event.beta + "
G:" + event.gamma+ "
_:" + event.absolute );

function render() {
    window.requestAnimationFrame( render );
    $("body").css( "background-position", bodyCSS);
    $(".content").css( "-webkit-transform", contentCSS);


An Icon Screen with Multiple Layers of Parallax Motion

The second example builds upon this first example. It is nearly identical, except that an additional layer of clouds has been introduced between the background image and the foreground icons.


When viewing the code, you will see that an additional div with the class “clouds” has been introduced before the “content” div.

    <div class="clouds"></div>
    <div class="content">

In the JavaScript for this second example, an additional CSS style/position is calculated for the clouds layer, also based upon the device orientation information.

var xPosition = -(gamma * increment);
var yPosition = -(beta * increment);
cloudsCSS = (-100+3*xPosition) + "px " + (-100+3*yPosition) + "px";
contentCSS = "translate3d( " + (-xPosition) + "px, " + (-yPosition) + "px, " + " 0px)";

These styles are again applied within the requestAnimationFrame render loop.

function render() {
    window.requestAnimationFrame( render );
    $("body").css( "background-position", bodyCSS);
    $(".content").css( "-webkit-transform", contentCSS);
    $(".clouds").css( "background-position", cloudsCSS);

An Interactive App with Parallax Motion and a Scrolling Background

So far we’ve just been looking at basic examples of parallax motion based upon the device’s orientation – this is still a far cry from a “real” application, so let’s take a look at our last example. In this example we’ve got parallax motion based upon device orientation, and we’ve also got parallax scrolling of content based upon the depth of navigation/user interaction. As the user drills deeper into content within the application, the background scrolls to show additional depth, much like the parallax scrolling that is used throughout Windows Phone devices. If you’re not quite sure what I’m describing, definitely check out the video above.


The basic techniques here are again more or less the same as the first example. We have an HTML structure for the UI elements inside of the “content” div, and the background animation is achieved by changing the background-position CSS for the <body> tag. The horizontal position of the background just also happens to be based upon the depth to which the user has drilled into the application experience. The other major difference is that any CSS style changes are only applied if the CSS values have actually changed – this reduces additional computation from applying unnecessary CSS style changes on the requestAnimationFrame interval. The “slide” transition from one view to another is achieved purely using hardware accelerated CSS animations and transitions. Check out this example from fellow Adobe evangelist Christophe Coenraets for detail how the hardware accelerated page transitions were applied.

I’m not going to list all of the code right here, but be sure to check out the full source code for all of these examples on the github repository:

All of these examples use the Zepto.js library for simple DOM manipulation and touch interaction.

Testing the Examples

If you want to interact with these examples on your own devices, you’re in luck! Use the links below to test these examples, however please keep in mind that they are intended for a phone form-factor only, have only been tested on iOS and Android/Chrome browsers, and you’ll only see the parallax motion if you’re actually on a mobile device. I’ve seen the best performance on iOS devices.

  1. Simple parallax motion
  2. Multi-depth parallax motion
  3. Interactive parallax “app” with scrolling

If you’d like to take advantage of parallax user interface effects and device motion, but don’t want to have to manage interactions with the device motion API and accelerometer yourself, be sure to check out the open source parallax.js library, which also has some great parallax motion examples.

Photographs used in this example copyright Andrew Trice. Icons used in this example are of public domain via


Building a Parallax Scrolling Game with Pixi.js – Part 3

2013 – The Year in Web Development


7 thoughts on “Parallax UI for PhoneGap and Mobile Web Apps”

  1. Cool demo. At the very end of the video, you scrolled the android content with a tap and it’s performance looked horrible. That’s a shame.

  2. Hi!

    First of all, thank you for the in-depth article of yours. It sure saved a few hours of R&D here!
    I’d like to add, that we tweaked the performance of it a little more, using a web worker to do the optimized version of the calculations, I thought you might be interested 🙂

Comments are closed.