> Scrolling div for mobile webkit turns 3

iScroll

I’m pleased that my original iScroll was useful to many. In the past months I received dozens emails asking for new features and bug fixes. I think it’s time to start developing a new version of the scrolling div for mobile webkit with added functionalities.

I recently modified the structure of the blog to have easier access to my projects. The iScroll has now a dedicated page, please head to the iScroll project page to get the lastest updates.

I’ve been asked to publish a new version of iScroll even if in development phase. Here you have it, but keep in mind that we are in Alpha1, the script is very rough and not ready for production. Okay, we are finally out of alpha and I’m moderately proud to introduce Beta phase. Please consider that I’m now working on GhostTouch, a framework dedicated and optimized to touch enabled mobile devices. The iScroll is a stand alone version of the scroller I’m developing for GhostTouch.

First things first. iScroll was born because mobile webkit (iPhone and iPod touch mainly, but also Android and Pre) does not provide a native way to scroll inside a fixed dimensions overflow:scroll|hidden|auto element. This unfortunate situation prevents any web-app to have a fixed header and/or footer and a scrolling central area.

Luckily mobile webkit offers a powerful set of hardware accelerated css properties that can be used to simulate the missing functionality, so the iScroll development has started… But there’s no rose without thorn. Making the scroll feel native has proven more difficult than expected. Version 2.x of the script was good enough, but it was lacking a lot of features.

Enough blabbing. Have a look at the screencast I baked for you or point your mobile device to cubiq.org/dropbox/iscroll.

Update 2010/05/06 – 3.1 beta 1: The most requested feature has been finally added. When new content is added or removed from the scrolling area (eg: ajax calls) iScroll automatically sets the correct position to comfortably host the new contents. We are still in beta, please give feedback.

How to use

All you need to do is to initialize iScroll with something like: myScroll = new iScroll('id');, where id is the #id of the element that will be scrolled. You can place it on window.onload or document.DOMContentLoaded.

iScroll automatically detects if you need vertical, horizontal or both scrollbars, but you can force scrollbars hiding with the optional second parameter. Eg: myScroll = new iScroll('id', {vScrollBar: false, hScrollBar: false}); (this prevents both scrollbars to appear).

On orientation change iScroll also refreshes itself and detects if the scrolling area has changed in size. You should add your code to resize the elements on orientationChange as shown in the example.

Other considerations

I decided to remove the scrollbar shrinking effect (ie: when you scroll outside of the screen the scrollbars reduce in size). Can be done with little effort and some frameworks already implement it, but it’s an inconsiderate waste of resources –precious resources– for such a small feature.

The script should now work on Android, too (at least on version 2.1, please give feedback).

The momentum formula I’m using feels pretty natural, I use a completely rewritten (and ridiculously simple) algorithm. If deceleration doesn’t look natural to you, you can try to tweak friction and deceleration parameters on line 273 and 274.
Q: Why aren’t you adding feature X?
A: I’d like the script to work on older devices. Not everyone has a SnapDragon ;) Plus, I’d like to keep this script as bare bone as possible so it’s easier for you to customize it to your needs.

Q: I’ve developed feature X, may I send it to you? Will you add my code to your script?
A: Please do! It’s not guaranteed that I will add your feature to the script, but I’ll review all code you send to me (matteo [at] this domain). Consider that scripts will be released under MIT license, if this is a no-go for you, don’t send.

Q: I’m in a hurry and I need feature X to be added to your script ASAP. Can you help me?
A: Have you considered hiring me? (matteo [at] this domain)

Go to iScroll project page

/Share the joy

/Reactions

    • Author: Aresinferno
    • Posted on: 2009/11/30
    • At: 15:18

    Awesome work as usual.

  • I too noticed performance problems with scrollbar shrinking when I implemented my own scrollbar for iScroll 2.3. Moving is no problem because transforms are hardware accelerated, but changing the height of the scrollbar make the performance awful.

    I ended up with placing the scrollbar in a div with overflow set to hidden. That means you could just use transforms to move the scrollbar partially outside of the visible area of the div and effectively shrinking the height of the scrollbar.

    The only thing is that the scrollbar is rounded and the div is rectangular. So if you ‘shrink’ the scrollbar one side will be rectangular and the other side will be rounded. I solved this by placing little dots in the background color on top of the div in all four corners. This makes it look rounded, but it is a bit fragile, especially if you want do not have a solid background color. Still it works pretty good in my own app.

    Cheers,

    Niels

  • @Niels: I think the best thing we can do to shrink the scrollbars is by using -webkit-transform:scaleY(). Should work but probably rounded corners will be squashed. Not tried yet, but should work pretty well.

  • @Matteo: Yes, I thought about that too and can see no real performance problems. In my own application I opted for the ‘dots’, simply because I wanted to have ‘real’ rounded corners and my background color is pretty stable. But for a more stable solution I would try scaleY instead.

    • Author: Mickey Shine
    • Posted on: 2009/12/01
    • At: 02:31

    Thank you for your great work. I am gonna give it a try now!

  • Social comments and analytics for this post…

    This post was mentioned on Twitter by sponso_RING: Scrolling div for mobile webkit turns 3 | Cubiq.org: If you need a new feature not in the to-do list, the intellectual p http://url4.eu/r0IP

    • Author: Adam
    • Posted on: 2009/12/01
    • At: 08:21

    I’m curious how one might go about using scrolling with multiple divs using iscroll.js. I’ve played around with it a little using 2.3 and haven’t had any luck so far, but I feel like I’m missing something pretty simple.

    For example, in a PhoneGap app I’m working on, I’ve got an absolute-positioned div that slides into visibility from the left when the user taps an item in the original scrolling div. If I wanted to scroll the second div, how would I go about doing so?

  • @Adam, you can create as many instances of the iScroll as you want (or at least as many as the iPhone can handle). Have a look:
    http://cubiq.org/dropbox/iscroll/2scrolls.html

    • Author: Aresinferno
    • Posted on: 2009/12/01
    • At: 12:53

    Personally I wouldn’t create new instances of iscroll. I would have it so all diva with an iscroll class could be scrolled. You wouldn’t need to initialize it more than once, only refresh it ontouchstart of a new element.

    As for the scrollbars, you should have a parent element that is 2px smaller than the scrolling div on the top and the bottom and then give it overflow hidden and a radius on the corners. When the scrollbar goes out of the boundaries, it will appear to get shorter and not just get cut off with a flat edge. Then you would only need to edit the height of the scrollbar when it refreshes and you can limit how far it can go out of the boundaries so that it doesn’t go more than a circle. If you wanted to be really exact you could even add a little White go around the scrollbar and have add one to the far end of the overflow container when it goes out of bounds.

    Also, you should add a zoom effect that allows you to zoom in on whatever is in the scrolling div using pinch gestures.

  • hi Aresinferno, thanks for your feedback. I’d like to test the scale transition first. It sounds more logical and doesn’t need additional markup. The rounded container is a brilliant idea, though.
    Regarding the zoom, I don’t think it will be implemented, not in the core version at least. Maybe I could add some plugin system. I’d like to release even the scrollbars as a plugin.

    • Author: Adam
    • Posted on: 2009/12/02
    • At: 01:01

    @Matteo, thanks for the heads up. I’ll give it a try using your example.

    • Author: Jake
    • Posted on: 2009/12/02
    • At: 18:35

    Thank you for this slick piece of code.

    Works great, easy to implement. I’m actually using it inside a PhoneGap App.

    Horizontal bouncing is the only “bug” visible for me, and isn’t an issue.

    Thanks again!

    • Author: Alex
    • Posted on: 2009/12/03
    • At: 00:29

    Great script however i ran into an issue when i placed a tag in it. It seems to float over everything and ignore the scrolling. Any ideas?

  • Alpha3 is out, now you can turn on/off scrollbars individually.
    Ex:

    // Horizontal scrollbar only (vertical is disabled)
    myScroll = new iScroll(document.getElementById('scroller'), 'x');
    
    // Vertical scrollbar only (horizontal is disabled)
    myScroll = new iScroll(document.getElementById('scroller'), 'y');
    
    // Scrollbars disabled
    myScroll = new iScroll(document.getElementById('scroller'), 'none');
  • @Aresinferno, A parent element with rounded corners and overflow hidden will not work. The child element will still clip using a rectangle and not take the rounded corners of the parent into account. It’s a bug in Webkit.

  • @Niels: DOH! It was too good to be true :)

    • Author: Aresinferno
    • Posted on: 2009/12/07
    • At: 18:58

    @Niels,

    Seriously? And I thought webkit was the king and it can’t even get something as obvious as this correct. There must be some kind of suitable solution.

    • Author: Udi
    • Posted on: 2009/12/07
    • At: 19:19

    The drop down problem still exist in this version, I suggest adding the following code at the beginning of handleEvent:
    var theTarget = e.target;
    if (theTarget !== null && theTarget.tagName === ‘SELECT’) {
    return false;
    }

    • Author: timtim
    • Posted on: 2009/12/09
    • At: 05:43

    man, you’re good.

    but, lets say you need only veritcal scrolling. it seems easier to track a Y-axis swipe, and use a CSS animation with a default distance and ease-out. Boy, its crazy that position:fixed isn’t properly supported.

  • @timtim: you mean no acceleration? Just a default distance? Unfortunately it wouldn’t feel natural (already tried :) ).

    I agree that it’s crazy the amount of JS needed to do such a simple task. If Apple can’t make position:fixed work at least they could introduce a CSS property like: -webkit-scroll: x|y|auto|none

  • it’s devastating the quantity of bugs in css rendering of the mobile webkit… The scrollbars scaling is becoming a pain in the arse.

    • Author: Udi
    • Posted on: 2009/12/15
    • At: 09:49

    great job man!
    any estimates on iscroll3 updates?

  • @Udi, I finally found a way to have those damned scrollbars shrink. Today I’ll publish an update, stick around.

    • Author: Udi
    • Posted on: 2009/12/15
    • At: 10:41

    Thanks man!!!
    And again, great work!

  • I uploaded a new version of the script which supports the scrollbars shrinking. It’s still buggy but it works, I’ll debug it in the coming days. Unfortunately, as noted by another user, round corners do not clip the webkit-transition. I also tried with webkit-mask property with no success. Scaling the scrollbars would have been perfect, but there’s no way not to have the round corners to squash. So a lot of hackery is needed to shrink the scrollbars.
    The solution is to move the scrollbar outside of a overflow:hidden container and recreate the rounded corners with an overlaying small rectangle. A pain in the butt, let me say it! And still not perfect. Any other ideas?

  • @Matteo How about splitting the scrollbar into three parts. First a div with half a circle. Then a div for the body of the scrollba. Finally again a div with half a circle. To change the size would be relatively simple. To move the rounded corners you can use a translate transform. To change the height of the body you could use a scale transform. And the best thing is everything should still be hardware accelerated.

  • @Niels: it’s not easy to have the scaling body to match the translating corner (you know floats rounding is not our friend). But maybe I found another way using background images. I’ll test it later. Today I also played with a similar code by Apple and I’m pleased to see that their implementation has more bugs than mine :P

    • Author: Aresinferno
    • Posted on: 2009/12/16
    • At: 17:16

    Sorry Matteo but apple has outdone you in some aspects. And me as it happens as I was developing a web kit but PastryKit has got the shrinking scrollbar bit almost perfect, along with everything else.
    http://ajaxian.com/archives/pastrykit-an-iphone-webdev-library-from-apple

  • @Aresinferno: that is the code by Apple I was playing with. But it has many issues (consider that iScroll3 is alpha stage) and lacks some functionality but most important it’s not MIT licensed, you can’t actually use it ;)

    • Author: Aresinferno
    • Posted on: 2009/12/16
    • At: 17:30

    @Matteo But that won’t stop people picking it apart or even some using it.

  • Scrolling on iphone 3g is pretty choppy with PastryKit.. Don’t know if it’s the case with iscroll for the same content..

    • Author: Tom Pace
    • Posted on: 2009/12/17
    • At: 03:46

    I created this last night in 2 hours:

    http://www.youtube.com/watch?v=AVZ0Jq54GP8

    Matteo – Your code helped me out way back months ago, and I posted way back, having fixed the stall that happens when dragging off the bottom of the touch screen..

    I didn’t even know pastrykit existed until after I made this scrolling demo.

    • Author: Dave
    • Posted on: 2009/12/17
    • At: 19:18

    Matteo, does your newest version address the issue with text input pushing the footer div up the page, requiring the user to tap the status bar to scroll everything back into view?

    That’s the only thing keeping this from being a killer script (oh who am I kidding, it’s already pretty killer!)

    Great job so far!

    • Author: Tom Pace
    • Posted on: 2009/12/18
    • At: 19:20

    I saw you had code commented out at the bottom of onTouchMove for launching the touch end event.
    That code is very similar to the fix I created for swiping off the bottom of the screen. I created this for v2 of iscroll, but I have updated it for iscroll v3.

    “Prevent the scrolling to lock when swiping outside of the screen”:
    within iScroll (el, scrollbars), I put this:

    this.element.iScroll = this;	// Let DOM have access to the iScroll object
    

    after this.element = typeof ….

    at the bottom of onTouchMove, there is a need to introduce timers again (sorry!) but it does what is needed (please note, the value-check on startY is to handle very-fast swipes whose last onTouchMove event was not close to the bottom of the screen):

    // Fix for touch-move off bottom of screen not firing touchend event
    if (typeof(this.stopScrollTimeout) != "undefined") {
    	clearTimeout(this.stopScrollTimeout);
    }
    orient = Math.abs(window.orientation);
    if ( (orient == 90 &&  this.startY > 90) || (orient != 90 &&  this.startY > 250) ){
    	this.stopScrollTimeout = setTimeout( function() { t=e.targetTouches[0].target; t=(t.nodeType==3?t.parentNode:t);t.iScroll.checkOutOfBounds(e);}, 300);
    }
    

    Between onTouchMove and onTouchEnd, I placed this function (note, I replaced my code for the function with a duplication of your code from the bottom of the onTouchMove, to prevent confusion):

    checkOutOfBounds: function(e) {
    	var theEvent = document.createEvent("TouchEvent");
    	theEvent.initEvent('touchend', true, true);
    	this.element.dispatchEvent(theEvent);
    	return false;
    },
    

    Hope that helps.

    • Author: paul
    • Posted on: 2010/01/11
    • At: 02:50

    I’ve designed a carousel for a webapp game. How would I go about “locking” an axis meaning if i just want it to scroll left and right and not have it dragged up or down (Y-axis) is there a way to do this. I can’t for the life of me figure out how to prevent this in the code.

    thanks in advanced!

    paul

    • Author: paul
    • Posted on: 2010/01/11
    • At: 04:36

    okay perhaps i’ve spoked too soon. to achieve the desired effect i spoke about (locking an axis so that it doesn’t move if those bounds aren’t specified) replace

    this.element.style.webkitTransform = ‘translate3d(‘ + this._xPos + ‘px, ‘ + this._yPos + ‘px, 0)’;

    with

    if(this.scrollbars.x && this.scrollbars.y) {this.element.style.webkitTransform = ‘translate3d(‘ + this._xPos + ‘px, ‘ + this._yPos + ‘px, 0)’;}
    if(typeof(this.scrollbars.x) == ‘object’ && typeof(this.scrollbars.y) == ‘undefined’){this.element.style.webkitTransform = ‘translate3d(‘ + this._xPos + ‘px, 0px, 0)’;}
    if(this.scrollbars.x == ‘undefined’ && this.scrollbars.y){this.element.style.webkitTransform = ‘translate3d(0px, ‘ + this._yPos + ‘px, 0)’;}

    im sure theres a better way of going about this, but this simply just works.

    • Author: paul
    • Posted on: 2010/01/11
    • At: 10:12

    oop, paste this instead:

    if(typeof(this.scrollbars.x) == ‘object’ && typeof(this.scrollbars.y) == ‘object’) {this.element.style.webkitTransform = ‘translate3d(‘ + this._xPos + ‘px, ‘ + this._yPos + ‘px, 0)’;}
    if(typeof(this.scrollbars.x) == ‘object’ && typeof(this.scrollbars.y) == ‘undefined’){this.element.style.webkitTransform = ‘translate3d(‘ + this._xPos + ‘px, 0px, 0)’;}
    if(typeof(this.scrollbars.x) == ‘undefined’ && typeof(this.scrollbars.y) == ‘object’){this.element.style.webkitTransform = ‘translate3d(0px, ‘ + this._yPos + ‘px, 0)’;}

    • Author: Mungeroo
    • Posted on: 2010/01/13
    • At: 16:33

    Is there a way to save the last scroll position so that when the page is refreshed it can position to its previous point?

  • Awesome, awesome script!
    I have seen others, but they do not do the job as well or as neatly.

    Is it possible to limit scrolling to just one axis?

    FYI, iScroll is compatible with “Overscroll” ( http://azoffdesign.com/plugins/js/overscroll )
    If you call overscroll on the wrapper, then PC users can scroll the DIV with a click and drag motion too.

    This enables iScroll content to be fully cross browser and behave similarly.

    I have a demo here:

    http://placebook.tv/isgmfb.php

    iScroll is used for the main menu and if you click help in the main menu, the help page is an iScroll too.

    This is tested on:
    Desktop Firefox
    iPhone Safari (Normal)
    iPhone Safari (“Homescreen App” mode)
    Desktop Safari
    Android
    It should look identical* in all. It handles any screen resolution and also change of dimensions (rotate on mobile, resize on desktop) in all.
    (* In desktop browsers, in the help menu, the scroll bar is shown deliberately, I prefer it that way)

    Just onhe thing – in the help menu iScroll, why is there no styled scrollbar like there is on the main menu iScroll?

    • Author: laura
    • Posted on: 2010/01/16
    • At: 18:16

    Hi.

    Thank you for this. :)

    Quick question…I started a website, http://www.giroapps.com. in the overview of the apps, i have an iframe. i used your code so it’ll port well on the iPhone. However, i can’t seem to make it work.

    I added the and around the lines in my html (not in the html that the iframe gets its content from). I also added:

    to the head of that same html file. Added the js file, too.

    I don’t know what i’m doing wrong…hope someone can help me with this.

    If any angel wants to help me with this, please email me at: lauranoel at me dot com, so i can send my code. :)

    Thanks in advance!! :)

    • Author: laura
    • Posted on: 2010/01/16
    • At: 21:27

    I finally got it to work on the iPhone. Problem now is the iFrame on safari isn’t moving. When i use it on my iPhone, the iframe scrolls perfectly.

    this is my html:

    Your browser does not support iframes.

    new iScroll(document.getElementById(‘scroller’));
    window.onload = function() { setTimeout(function(){ new iScroll(document.getElementById(‘scroller’)) }, 100) };

    this is my css:
    div#wrapper {
    clear: both;
    height: 297px;
    width: 421px;
    margin-top: 214px;
    margin-left: 333px;
    position: absolute;
    z-index: 5;
    }

    div#scroller {
    clear: both;
    height: 297px;
    width: 421px;
    margin-top: auto;
    margin-left: auto;
    position: absolute;
    z-index: 4;
    }

    hope someone can help me figure out why it isn’t working on safari anymore.

    Thanks in advance!! :)

  • Much more full featured demo:
    http://placebook.tv/isgmfb-0.2.php

    Interestingly though, I am having trouble scrolling past anything created that went outside the browser viewport. Is this a bug or something maybe? It’s probably me…

    • Author: bexonder
    • Posted on: 2010/01/17
    • At: 14:04

    hi matteo

    referring to:

    http://cubiq.org/scrolling-div-on-iphone-ipod-touch/5#comment-8

    respectively

    http://cubiq.org/scrolling-div-on-iphone-ipod-touch/5#comment-9

    i still have the problem above, how can i change the top attribute instead of -webkit-transform element on screen?

    i tried: this.element.style.webkitTransform = ‘translate3d(0, ‘ + this._yPos + ‘px, 0)’;

    but simply this obviously doesn`t work. unfortunately i can´t find a solution. could you plaese show me yours?

    thanks a lot

    • Author: Martin
    • Posted on: 2010/01/20
    • At: 18:09

    Hi,

    I have an intranet version running iWebKit and it works well… I run it in fullscreen mode
    but when adding the iScroll all of my links are opened in safari instead of keeping the new url in fullscreen mode.

    What am I doing wrong?

    Thanks
    /Martin

    • Author: Jason
    • Posted on: 2010/01/20
    • At: 22:17

    Has anyone been able to get this to work correctly on Android? I just tried it on the Nexus One, and it works, but only for the first scroll gesture. After that, webkit goes back to scrolling the entire page again.

    I’m hoping its a simple fix! Please let me know if you have any ideas.

    • Author: Pilar
    • Posted on: 2010/01/20
    • At: 22:33

    I am using iscroll for a iphone-like application using WebApp.net as the framework.
    Well, I’m running across an issue that I hope I can get help with.
    I am running iscroll in the third page of my application, that means that the div that has the iscroll is not the div in display when the application is being loaded. I have set a delay of 3 seconds to give iscroll enough time to load after all the other elements of the applications are being loaded but iscroll is still not responsive.
    Iscroll is only working when I refresh the application when the div that contains iscroll is displayed on the iphone.
    Does anybody have any suggestions in how to get iscroll to respond, or be ‘active’ for a lack of a better term even when the div that contains it is not being displayed at loading time?

    \

    • Author: jonPrecise
    • Posted on: 2010/01/21
    • At: 18:27

    Awesome script!
    yah im one of those people who only post when there’s a problem..
    last night, I was marking up some manual image crops in an iscroll with a few individual spans (( display:block, overflow: hidden )) and just needed to put them in line.
    Of course I then just floated them all to the left. Looks perfect.. S#!& , displays fine with floats but the iscroll height is off , 0 height? after scrolling down it pops right back to the top like there is no content ..
    Tried a few things to adjust the height, fixed positioning elements further down , no results.. the floats seem to be offsetting something.
    For about 30 minutes or so I tried every other side by side technique I could think of including just throwing everything in the old table schema , tables display fine (( but oddly enough there seems to be a mobile safari bug where images intermittently are hidden untill touched when in a td .. ))
    so damn .. no floats, no tables, can’t use display:inline, will kill the crop effect , ok display:inline-block seemed to do the trick.
    I double check it this morning to and it seems fine.. 90% of the time .. now randomly ( say 1 out of 10 times ), when the iscroll is initiated.. it starts midway through the content, the first line of spans are hidden unless you scroll Up..
    If anyone has dealt with this scenario, feel free to school me.
    and Matteo, again awesome script, sorry my first post is about an issue..

    • Author: jonPrecise
    • Posted on: 2010/01/21
    • At: 19:23

    false alarm,
    I swapped the spans with divs , corrected the mid-scroll issue.
    although.. then the images seemed to load whereever they wanted and not inline.
    for test, i threw some color on the div backgrounds to check positioning and they load perfect before the images arrive.
    this prolly has more to do with mobile safari than with iscroll im sure.
    considering the divs load in correct position, I just applied the images individually to the div background .
    floating inline image crop effect successful.
    just another css nightmare.. on to the next one

    • Author: Don Jayamanne
    • Posted on: 2010/01/25
    • At: 03:05

    I’ve been using an older version of this script & as reported by other users I too have come across the issue where the text in input boxes gets garbled.
    Has this issue been resolved in the latest version?
    Thanks