title: iScroll Scrolling Past Bottom?
body: <p><s>You can easily see the problem on the first page here: <a href="http://m.vancouverislandlife.com/" rel="nofollow">http://m.vancouverislandlife.com/</a></p>
  
  <p>Scroll down (slide up) and allow the content to leave the page, and it doesn't bounce back and is lost forever. However, on pages whose content <em>does</em> overflow the page and is therefore supposed to be scrollable, the scrolling works correctly (see Accomodations > b&amp;b's and scroll down for an example of this).</p>
  
  <p>I noticed that on my computer, the scrolling on the first page is always stuck at <code>-899px</code>. I can't find anybody else who's experienced this problem and no matter what I try, I just can't fix it! Help!</p>
  
  <p>(It's not exactly urgent, however, as the target audience of iPhones and iPod Touches aren't affected by this since they have so little screen room.)</s></p>
  
  <p>Okay, new problem. To solve the iScroll issue, I just created a custom script. However, it's not working correctly on the <em>actual device</em>. On desktop browsers, it works just fine. On mobile, it occasionally jumps back to the top and won't recognize some touches. This is probably because of the way I cancelled the default event and had to resort to a bit of a hack. How can I fix this? (Yup - simple problem for a +500 bounty. Not bad, huh?)</p>
  
  <p>Here's the script, and the website is at the usual place:</p>
  
  <pre><code>function Scroller(content) {
      function range(variable, min, max) {
          if(variable &lt; min) return min &gt; max ? max : min;
          if(variable &gt; max) return max;
          return variable;
      }
  
      function getFirstElementChild(element) {
          element = element.firstChild;
  
          while(element &amp;&amp; element.nodeType !== 1) {
              element = element.nextSibling;
          }
  
          return element;
      }
  
      var isScrolling = false;
      var mouseY = 0;
      var cScroll = 0;
      var momentum = 0;
      if("createTouch" in document) {
          content.addEventListener('touchstart', function(evt) {
              isScrolling = true;
              mouseY = evt.pageY;
              evt.preventDefault();
          }, false);
          content.addEventListener('touchmove', function(evt) {
              if(isScrolling) {
                  evt = evt.touches[0];
  
                  var dY = evt.pageY - mouseY;
                  mouseY = evt.pageY;
                  cScroll += dY;
                  momentum = range(momentum + dY * Scroller.ACCELERATION, -Scroller.MAX_MOMENTUM, Scroller.MAX_MOMENTUM);
  
                  var firstElementChild = getFirstElementChild(content);
  
                  content.style.WebkitTransform = 'translateY(' + range(cScroll, -(firstElementChild.scrollHeight - content.offsetHeight), 0).toString() + 'px)';
              }
          }, false);
          window.addEventListener('touchend', function(evt) {
              isScrolling = false;
          }, false);
      } else {
          content.addEventListener('mousedown', function(evt) {
              isScrolling = true;
              mouseY = evt.pageY;
          }, false);
          content.addEventListener('mousemove', function(evt) {
              if(isScrolling) {
                  var dY = evt.pageY - mouseY;
                  mouseY = evt.pageY;
                  cScroll += dY;
                  momentum = range(momentum + dY * Scroller.ACCELERATION, -Scroller.MAX_MOMENTUM, Scroller.MAX_MOMENTUM);
  
                  var firstElementChild = getFirstElementChild(content);
  
                  content.style.WebkitTransform = 'translateY(' + range(cScroll, -(firstElementChild.scrollHeight - content.offsetHeight), 0).toString() + 'px)';
              }
          }, false);
          window.addEventListener('mouseup', function(evt) {
              isScrolling = false;
          }, false);
      }
  
      function scrollToTop() {
          cScroll = 0;
          content.style.WebkitTransform = '';
      }
  
      function performAnimations() {
          if(!isScrolling) {
              var firstElementChild = getFirstElementChild(content);
              cScroll = range(cScroll + momentum, -(firstElementChild.scrollHeight - content.offsetHeight), 0);
              content.style.WebkitTransform = 'translateY(' + range(cScroll, -(firstElementChild.scrollHeight - content.offsetHeight), 0).toString() + 'px)';
              momentum *= Scroller.FRICTION;
          }
      }
  
      return {
          scrollToTop: scrollToTop,
          animationId: setInterval(performAnimations, 33)
      }
  }
  
  Scroller.MAX_MOMENTUM = 100;
  Scroller.ACCELERATION = 1;
  Scroller.FRICTION = 0.8;
  </code></pre>