Native scrolling in jQuery Mobile/PhoneGap applications

In one of my previous blog posts I covered how to fix flickers and jumps during page transitions when using jQuery Mobile with PhoneGap. The good news is that flickers were eliminated with latest release of PhoneGap 2.1 and its departure from using IFrame for JavaScript to Native bridge. Unfortunately issue of 1px jumps is still there, but that is by design in jQuery Mobile. So this means my solution with additional div element hosting application content is still valid.

Unfortunately my approach has a drawback of loosing jQuery Mobile out-of-the-box content scrolling. A workaround I found for this is to use absolute positioning and native css declarable scrolling. By native css declarable scrolling I understand using overflow property with scroll value and -webkit-overflow-scrolling set to touch. You have to be careful when using these, as it may not work on all devices. I know iOS supports it from version 5 and above. In case of Android only overflow: scroll is actually working, which means you will not have rubber band effect, but your content will actually scroll – which in case of Android is often good enough 😉 For devices that don’t support it you may want to use Overthrow library which nicely polyfills it, or any other libs like: iScroll, Scrollability or ScrollView.

The snippet below demonstrates it in details, you can also run it from here. As you can see I had to absolutely position header and content elements. In addition I added .scrollable css class that enables native scrolling of its content. One thing to note here is that I had to enforce hardware acceleration of scrolled elements with -webkit-transform: translateZ(0px); property. This only works on iOS so make sure you don’t use this declaration on Android. BTW Apple has fixed it in iOS 6 and enforcing hardware acceleration will not be necessary in the future.

<!DOCTYPE html>
<html>
<head>
    <title>Scrollable Content Demo</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- jQuery Mobile styles -->
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />

    <!-- Fix for scrolling on iOS prior to iOS 6 -->
    <style type="text/css">
        body {
            margin: 0;
        }

        div#container {
            position: absolute;
            width: 100%;
            top: 0;
            bottom: 0;
        }

        div[data-role="header"] {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
        }

        div[data-role="content"] {
            position: absolute;
            top: 41px;
            bottom: 0;
            left: 0;
            right: 0;
        }

        .scrollable {
            overflow-y: scroll;
            -webkit-overflow-scrolling: touch;
        }

            /* iOS specific fix, don't use it on Android devices */
        .scrollable > * {
            -webkit-transform: translateZ(0px);
        }
    </style>

    <script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
    <script type="text/javascript">
        $(document).one('mobileinit', function () {

            // Setting #container div as a jqm pageContainer
            $.mobile.pageContainer = $('#container');

            // Setting default page transition to slide
            $.mobile.defaultPageTransition = 'slide';

        });
    </script>
    <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>

</head>
<body>
<div id="container">

    <div data-role="page">
        <div data-role="header" data-position="fixed">
            <h1>Scrollable Content</h1>
        </div>

        <div data-role="content" class="scrollable">
            <ul data-role="listview">
                <li>
                    <a href="#">
                        Hello World!!!
                    </a>
                </li>
            </ul>
        </div>
    </div>

</div>
</body>
</html>


19 comments

  1. Pingback: Fixing flickers & jumps of jQuery Mobile transitions in PhoneGap apps | outof.me
  2. Alex

    This is great thanks a million!!

    One thing I noticed though is I had to add bottom: 58px; on div[data-role=”content”] to ensure my footer did not overlay the bottom of my content when scrolling right to the bottom.

    Why jQueryMobile dont fix this whole issue once and for all I don’t know!

    Thanks again!

  3. Ben

    Great post! I can see this being extremely helpful to those who wish to create native apps with jQuery Mobile, and then PhoneGap. Thank you for taking the time to write this up.

    I made simple interface-building tool for jQuery Mobile (shameless plug) called Codiqa, which let’s you quickly put together a working prototype using jQM components. It’s a great way to get an idea off the ground. Would love to have your feedback on it! :)

    Thanks!

  4. Charly

    Works great on Android 4 but not on Android 2.2. or 2.3.3 The size of the data-role content container is correct, but you are not able to scroll down.

  5. Yves

    Problem is still, when you use

    /* This code prevents users from dragging the page */
    var preventDefaultScroll = function(event) {
    event.preventDefault();
    window.scroll(0,0);
    return false;
    };
    document.addEventListener('touchmove', preventDefaultScroll, false);

    In your example you don’t need the above code, because the whole page is scrollable. But what do you do if you need an element in a page to be scrollable and not the whole page.

  6. Armix

    Thank you for an excellent post!!
    That fixed the problem I had with my listview :
    .scrollable {
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
    }

    Thanks again!

  7. Mark Rummel

    This worked for my jQueryMobile+Phonegap Build app. Thank you very, very much!

    However, it seems to have broken the following code:

    $('html, body').animate({scrollTop: $('#voteHeader').offset().top}, 2500);

    The code above should scroll down the page to the div with an id of “voteHeader”. However, once I implemented the native scrolling solution you mentioned above, it stopped working.

    I have tried multiple things, but nothing seems to be working. Here are some of the things I’ve attempted:

    $('#container').animate({scrollTop: $('#voteHeader').offset().top}, 2500);
    $('html, body, #container').animate({scrollTop: $('#voteHeader').offset().top}, 2500);
    $('.scrollable').animate({scrollTop: $('#voteHeader').offset().top}, 2500);
    $(".scrollable").animate({ scrollTop: $("#voteHeader").scrollTop() }, 2500);

    Any thoughts on what I can do to be able to scroll down the page using javascript?

    I’m using jQuery 1.8.2, jQuery Mobile 1.2.0, and Phonegap 2.2.0 (via Build).

    Thank you! -Mark

  8. amer deep

    Really awesome, I have wasted lot of time with iscroll because I need scroll for left slide menu (panels in JQM) but it takes it for whole page or either whole panel instead of particular element. I have gone through many sites and many solutions but it wont work as per expected. But your 4 line of class rocks, many thanks to you for sharing this solution.

  9. Tom M

    Any suggestions on the best approach to get scrolling to work on Android 2.2 or 2.3.
    I need an element to be scrollable not the whole page (as in this code example).
    My problem occurs when I apply a “height” to the Div Containing the listview; scrolling
    stops. No issues with scrolling the whole page. Thanks in advance for your help.

  10. alain

    Am I missing something ? When I run your snippet in phonegap 2.6, the header moves along with the list when I scroll down. Shouldn’t the header stay at position 0,0 and never move ?

  11. Ashish

    Thanks for posting this article but this fix is not working for my app. I am using jQuery Mobile. I have a page which opens as overlay. There are two divisions (one for overlay and one for overlay content). For overlay position is given ‘fixed’ and for overlay content the overflow is given ‘scroll’. The content’s height is more than that of overlay so in order to let user see the complete content it should be scrollable but it’s not allowing users to scroll the overlay content. As you already mentioned ‘-webkit-overflow-scrolling: touch’ doesn’t work on android (or it is not supported I guess). Request you to help me get a workaround of this scrolling issue. Thanks in advance.

  12. Ashish

    I forgot to mention one point. The targeted devices of my app are android tablets. I am testing the app in an android tablet version of which is 4.1.2.

  13. Chad Coward

    I have a problem when using this method on Mobile Safari (iPad 2) with JQM 1.3.1. When focused on an input, a large white background seems to cover half of the screen, sometimes more sometimes less. I changed the body’s color to black and the background also changed to black. I’m assuming the body is somehow reacting, for some reason? Have you heard of this?

https://outof.me

Leave a Reply to Alex Cancel reply

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>