Monday, September 7, 2015

jQuery Mobile Scrolling



jQuery Mobile is a great cross-platform web development framework, but it isn’t perfect. Its need to be cross-platform limits its ability to do a few things, such as interior scrolling. Native applications can easily do interior scrolling. Android and iPhone applications can easily leave the header and footer in place so users can scroll the interior vertically or horizontally. Luckily there is a way to add app-like interior scrolling to jQuery Mobile — a JavaScript plug-in named iScroll4.

iScroll 4


iScroll depends upon CSS transforms, which Internet Explorer doesn’t support so, sorry Windows Phone 7. iScroll has a lot of features besides scrolling, but we will save those features for another day and just concentrate on scrolling in this article. There are two versions of the iScroll plug-in: regular and lite. The lite version is less than half of the size of the regular version, and doesn’t support any extra goodies or the desktop. We will use the lite version in the demo program but if you want to use some of the extra goodies feel free to use the full version instead.

 What is actually happening is the content area extends from the top to the bottom of the viewport and the header and footer are position on top of it. I know you may be thinking that it is the same difference, but what happens if instead of wanting to vertically scroll the entire content area, you only wanted to scroll a subset, such as a <div> region or you want to scroll horizontally? In this case, using position:fixed on the header and footer won’t help you. You still need iScroll.

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. The location of the viewport is changed by iScroll using CSS3 transformations. iScroll also takes care of all of the users interaction with it. Once you set it up, iScroll does all of the grunt work. The trick is setting it up. Only one line of JavaScript is need to invoke iScroll, since the majority of the set up is the CSS style sheet.

An easy way to imagine iScroll is to think of the big scrolling region as the scroller and the smaller viewport region as the wrapper. Inside of the scroller are tiles.

Vertical scrolling

To scroll vertically we make the scroller’s height greater than its width. To determine the scroller’s height we use the following formula:

scroller height = (number of tiles + 1) * tile height


Horizontal scrolling


Because we set each <li> to float:left, the tiles will naturally stack side by side when given enough width to do so. Like the height above, the formula for the width is simple:

#verticalWrapper {
    width: 100%;     /* will be the same as the width of the content area */
    height: 240px;   /* will be changed to the height of the content area */
    overflow: auto;
}

#verticalScroller {
    width: 100%;
    height: 3240px;  /* max number scroll elements + 1 times their height */
    background-color: #f00;
}

#verticalScroller li {
    width: 100%;
    height: 120px;  /* this is the height of an individual element */
    border-top: 1px solid #ccc;
    border-bottom: 1px solid #fff;
}

Wrapping things


What we do is to determine the height of the window then subtract the heights of the header and footer from it. We then use JavaScript via jQuery’s CSS methods to update the wrapper’s height. Before we can get any valid dimensions we need to wait until jQuery Mobile triggers a pageshow event. Once it occurs it means JQM has initialized, is ready to render the page, and the dimension values are valid.

init = function () {
    width = $(window).width();
    height = $(window).height();
    headerHeight = $("header", $.mobile.activePage).height();
    footerHeight = $("footer", $.mobile.activePage).height();
    contentHeight = height - headerHeight - footerHeight;
};

var pageshow = function () {
        RocknCoder.Dimensions.init();
        // determine the height dynamically
        var dim = RocknCoder.Dimensions.getContent();
        $("#horizontalWrapper").css('height', dim.height);
        $("#verticalWrapper").css('height', dim.height);
    };

Smooth scrolling


With the proper CSS and HTML in place we activate iScroll by instantiating it with the new instruction in our pageshow event handler. Being good coders we also destroy our scroll in the pagehide event handler.

RocknCoder.Pages.verticalPage = (function () {
    var myScroll,
        pageshow = function () {
            myScroll = new iScroll('verticalWrapper');

        },
        pagehide = function () {
            myScroll.destroy();
            myScroll = null;
        };
    return {
        pageshow: pageshow,
        pagehide: pagehide
    };
}());

Popular Posts