iScroll is a small JavaScript library that allowed scrolling of elements on mobile Safari. Mobile Safari did not support scrolling of overflow contents before IOS 5 and iScroll made it possible. It works great although it is no longer necessary.

One thing that iScroll and Safari for IOS 5 still do not do is leave the frigging page alone when trying to scroll something that can’t scroll. The problem is that a web page is a scrollable element and the native rubbery feel that is applied to things that scroll makes the web page look like a web page, not a native app. A native app is not scrollable in it’s entirety so webapps look wrong in this regard. iScroll and IOS 5 do nothing to keep the entire page from having that rubbery feel even if the page is set to be 100% of the screen and no more.

To get rid of the rubbery feel for the whole page and make the webapp seem like a native app, I implemented some quick checks in the code to determine if the target of a scroll action has a certain CSS class, “allowscroll”, and I check to see if the element is already at it’s top or bottom depending on which way the move event is moving. It’s not the best implementation but it works. If the thing that is being scrolled is not one of my scrollable elements or if a scrollable element is already at it’s scroll limit, the default behavior of is prevented. Here’s some code:

            function TouchStartHandler( e )
            {
                lastScreenY = e.touches[0].screenY;
                firstScreenY = lastScreenY;
            }

            function TouchMoveHandler( e )
            {
                var target = e.target;
                while ( target.nodeType != 1 )
                    target = target.parentNode;

                var ScrollContainer = GetParentOfClass( target, "allowscroll" );
                if( ScrollContainer == null )
                {
                    e.preventDefault();
                    return;
                }

                var screenY = e.touches[0].screenY;
                if( screenY > lastScreenY )
                {
                    if( ScrollContainer.scrollTop == 0 )
                        e.preventDefault();
                }
                else if( screenY < lastScreenY )
                {
                    if( ScrollContainer.scrollTop + ScrollContainer.offsetHeight == ScrollContainer.scrollHeight )
                        e.preventDefault();
                }
                else
                    e.preventDefault();

                lastScreenY = e.touches[0].screenY;
            }

This code does a few things to figure out what is going on and it seems to work as expected in my simple webapp. It works for my own div element that holds lists and it works for the textarea element that has scrolling built in. The textarea element is interesting because it acts like the parent of the scrollable content even though there is no visible/accessible child element that is larger and is being scrolled. For my own div that scrolls, I control both the oversized scrolling element as well as the parent container. The code shows this difference.