jQuery Mobile is now few years old and while it’s a great HTML5 mobile framework it’s far from perfect.
 
It’s all around platform support also makes it limited in some specific fields. One of those actions is ability to scroll content while at the same time header and footer are fixed in place. The same ability exists and works in some other frameworks, like Sencha Touch and Kendo UI. I will show you how to do it in your jQuery Mobile application.
 
jQuery Mobile can’t do it on its own so we are gonna use one of a jQuery’s most useful traits, its large plugin collection. One of those plugins was originally born in 2008 to fill the lack of native scrolling in the mobile webkit browser. At that point it was a iOS webkit browser and we are talking about iScroll plugin. iScroll was created by developer Matteo Spinelli and is available for download in his web site.
 
iScroll is more then capable to do what it does best unfortunately this is not enough. jQuery Mobile has a specific page architecture which makes iScroll integration a rather big pain in the ass. Luckily some good soul has create a jQuery Mobile iScroll wrapper called iScrollView. It can be found here and it slightly lags behind currently available iScroll version.
 
So hop to the previously mentioned iScroll site and download iScroll version 4.2. Or if you are lazy (lets be honest, you came here for an easy fix) you will find everything at the end of this article.
 
 

Note: If this tutorial was helpful, need further clarification, something is not working or do you have a request for another Ionic post? Furthermore, if you don't like something about this blog, if something is bugging you, don't like how I'm doing stuff here, again leave me a comment below. I'm here to help you, I expect the same from you. Feel free to comment below, subscribe to my blog, mail me to dragan.gaic@gmail.com, or follow and mention me on twitter (@gajotres). Thanks and have a nice day!

PS. If you want my help, if possible (even if it takes you some time to do that), create a working example I can play with. Use Plunker for AngularJS based questions or jsFiddle for jQuery/jQuery Mobile based questions.


 

How it works

 
iScroll works by nesting a bigger region inside of a smaller one. The smaller region serves as a viewport into the bigger region. In theory, iScroll can scroll horizontally, and vertically at the same time.
 
In practice, users would not expect to be able to scroll diagonally, so we limit our scrolling to one direction at a time. It is by far the easiest and most user-friendly system I have come across to date. This is brilliant for getting your footer to stay fixed in the floating position.
 

Basic example

 
HTML:
 
<div data-role="page" id="index">
    <div data-theme="b" data-role="header">
        <h1>Index page</h1>
    </div>
    
    <div data-role="content">
        <div class="example-wrapper" data-iscroll>
            <ul data-role="listview">
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>                
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>                
            </ul>
        </div>	        
    </div>
    
    <div data-theme="b" data-role="footer">
        <h1>Footer</h1>
    </div>    
</div>       
 
CSS:
 
.ui-content {
    padding: 0 !important;
}

.ui-listview {
    margin: 0 !important;
}

.example-wrapper, .example-wrapper div.iscroll-scroller {
    width: 100% !important;
}
 
As you can see we have created a wrapper <div> and gave it class name .example-wrapper. It is placed inside a content <div> at a same time wrapping our content. We also gave it data-iscroll attribute. The JavaScript does some magic, and now the page has the nice effects that are common in native apps: bounce, and throw.
 
These are often referred to as “physics”, in case you’ve heard that and weren’t sure what it was referring to. You should also notice that we didn’t use javascript to do anything, everything is done in a background.
 
Working jsFiddle example can be found here: http://jsfiddle.net/Gajotres/CKSYJ/
 
 
Notes
 
  • Make sure you use data-tap-toggle=”false” if you don’t want goofy disappearing tolbars when the user taps on the toolbar!
  • Do not use data-tap-toggle=”false” for Navbars! This is an apparent bug in jQuery Mobile. data-tap-toggle is not possible for NavBars in any case, because the buttons cover the entire toolbar surface. There isn’t anywhere for the user to tap-to-toggle.
  • To use a persistent toolbar, assign the same data-id value to the toolbar in each page in which it appears. jQuery Mobile will move the toolbar out of the page temporarily during transitions, so that it will appear fixed
  • Scroll bar is not permanent in iOS devices, it will hide after few seconds of inactivity
 

Dynamic content

 
Let’s say we need to use an ajax call to add more content to our listview. Each time we add something, new content height needs to be propagated to iScrollView engine so it can resize accordingly. One more thing, while adding dynamic content, data-role=”content” <div> can no longer be used as a destination container. Just like with jQuery Mobile layout, iScrollView HTML content looks much different after page markup is enhanced.
 
For example, when you wrote:
 
<div data-role="content">
    <div class="example-wrapper" data-iscroll>
        <p>This is some content that I want to scroll</p>
        <p>This is some more content</p>
    </div>
</div>
 
Enhanced page markup looks like this:
 
<div data-role="content">
    <div class="example-wrapper" data-iscroll class="iscroll-wrapper">
        <div class="iscroll-scroller">
            <!-- If you included a pull-down under the wrapper, it will wind-up here -->
            <div class="iscroll-content">
                <!-- If you included no content above under the content div, then this div is empty -->
                <p>This is some content that I want to scroll</p>
                <p>This is some more content</p>
            </div>
            <!-- If you included a pull-up under the wrapper, it will wind-up here -->
        </div>
    </div>
</div>
 
So accordingly to this architecture, if we want to add more content it must be appended to the class=”iscroll-content” <div>. Example can be found below:
 
HTML:
 
<div data-role="page" id="index">
    <div data-theme="b" data-role="header">
        <h1>Index page</h1>
    </div>
    
    <div data-role="content">
        <div class="example-wrapper" data-iscroll>
            <ul data-role="listview">
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>                
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>
                <li><a href="#">Some link</a></li>                
            </ul>
        </div>	        
    </div>
    
    <div data-theme="b" data-role="footer">
        <h1>Footer</h1>
    </div>    
</div>    
 
CSS:
 
.ui-content {
    padding: 0 !important;
}

.ui-listview {
    margin: 0 !important;
}

.example-wrapper, .example-wrapper div.iscroll-scroller {
    width: 100% !important;
}
 
Javascript:
 
$(document).on('pagebeforeshow', '#index', function(){ 
    for(i = 0; i < 30; i++) {
        $(".example-wrapper div .iscroll-content").append('<a data-role="button">Button ' + i + '</a>');
    }
    $('[data-role="content"]').trigger('create');
    $(".example-wrapper").iscrollview("refresh");
});
 
Before enhancing iScrollView container, we first must enhance new jQuery Mobile content.
 
$('[data-role="content"]').trigger('create');
 
When jQuery Mobile content is fully enhanced we can proceed with iScrollView container enhancement.
 
$(".example-wrapper").iscrollview("refresh");
 
Working jsFiddle example can be found here: http://jsfiddle.net/Gajotres/952NJ/
 
 
Continue Reading

  • anas

    Thanks 🙂

  • Aegean BM

    iOS 7 dumped my satisfactory jqm app on its head.

    The last update to Matteo’s site was in June, so I’m a little leary of investing the time in iScroll only to see it fail on iOS 7. Have you tried iScroll on iOS 7? (Honest translation: I’m lazy, so I hope I can spend YOUR time for the price of a sincere thank you.)

  • Brad

    Great summary of iScroll and iScrollView. Love the examples as there isn’t a lot of information out there about marrying these with jQuery Mobile. Thanks for sharing!

  • Roberto Vargas

    I’ve been trying to implement iscroll in a web application with touch screen but I’m having issues.
    My problem is that when you drag/swipe up and down the selection gets clicked and I want users to scroll up and down without clicking on the button or selection until they “tap” the screen.
    I’ve tried several approaches to fix this but none seem to work.
    do you have any suggestions?

    thanks.

  • Juan Alpízar

    Excellent article, I had several issues due to jquery mobile native scrolling on an iOS application while dynamically adding content, and this plugin solved all of the issues.

    Thanks so much! 🙂

  • Lesz

    Hello,

    Can explain how to set the scrollable area height by percentage? For example, first div 30% and the rest of the screen height take up all by the scroller. I tried to see % to the div by its not working. Any advice?

    • If I can remember it correctly iScroll will not work inside DIV set with percentage height. Pure CSS solution will not work here, use jQuery or basic JavaScript, calculate 70% of height in pixels and set it to DIV containing scroller.

  • In your sample you also give some CSS code, but when you use it, it breaks the styling of some JQM elements and breaks design. Is there any way to overcome it?

    • Chage CSS as it suits you, only CSS that this code requires is:

      .example-wrapper, .example-wrapper div.iscroll-scroller {
      width: 100% !important;
      }

  • Lesz

    Hi, I have tried using iScrollview in my jQM project. I have problem with the height of the scroller. When I follow the exact example provided by: http://www.gajotres.net/using-iscroll-with-jquery-mobile/

    Everything working as expected. But if I would like to add a new DIV before or after the scroller, the height of the scroller will be push by the extra height of the new DIV.

    This is the jsfiddle of the problem: http://jsfiddle.net/lesliez/CKSYJ/115/

    I need the scroller to auto-adjust to the correct height after I add new DIV before or after the Scroller DIV.

    Please provide example/advice on how can I do so. Thank you.

  • Hi,
    After integration of iscrollview into my phonegap+jquerymobile android app I faced the problem that all list items begin running the click handler TWICE times. Does anyone know what is the problem?

    • Maybe you are facing multiple event triggering problem, it is a common problem related to jQuery Mobile. Just browse through my blog, I have an article dedicated to this problem.

      • Dhameer Govind

        Hi, what is your blog link?

        • You’re reading it just now 🙂

          • Dhameer Govind

            🙂 my bad. After not finding a solution I removed iScroll which solved the click issue. Now i’m stuck trying to make my app scroll

  • Lesz

    Hi,

    I try to use iscrollview inside “panel” but it doesn’t seem to worl. The page still scroll together with the panel content which I do not want that to happen. I hope to achieve to scroll only the panel content but the Page content remain still.

    Is there anyway I can do that? Please advice, thank you very much.

    • It should work, depending on jQuery Mobile version, I know I made a working example last year, you can find it at stackoverflow, just goggle it a bit.

  • Note that iScrollView is no longer needed:

    https://github.com/watusi/jquery-mobile-iscrollview/issues/118

  • The posted example deals with updating class related listview. How about updating an id of a listview by its name? I have multiple pages in my SPA and would like to use this, how can I achieve that please?

    • Sorry I don't understand what are you trying to achieve?

  • Jan Hudak

    Dear Gajotres,
    i am using iscroll for pull down to refresh, on listview, and have bind swiperight and swipeleft events on body or ui-content, but when i applied iscroll, swipeleft and right events stopped working over listview and over ui-content area.
    Could you help ?
    thanks.
    Jan

    • Unfortunately, I can’t help you right now, I haven’t used jQuery Mobile in a long long time. My advice, ask at stackoverflow or official jQuery Mobile forum.