Search code examples
javascriptprototypejs

scroll page so that element is visible


I've just tried prototype's scrollTo function and as the documentation states, it

Scrolls the window so that element appears at the top of the viewport

I'd like a function that

  1. only scrolls if the element is not entirely visible within the viewport
  2. scrolls so that the element appears at the center of the viewport

does anyone know of such a function in prototype, scriptaculous or stand-alone?


Solution

  • I guess you need something like this (demo):

    window.height

    function getWindowHeight() {
      var body  = document.body;
      var docEl = document.documentElement;
      return window.innerHeight || 
             (docEl && docEl.clientHeight) ||
             (body  && body.clientHeight)  || 
             0;
    }
    

    Scroll

    function scrollElemToCenter(id, duration) {
      var el = document.getElementById(id);
      var winHeight = getWindowHeight();
      var offsetTop = el.offsetTop;
      if (offsetTop > winHeight) { 
        var y = offsetTop - (winHeight-el.offsetHeight)/2;
        // wo animation: scrollTo(0, y);
        scrollToAnim(y, duration);
      }
    }
    

    Animation (optional, you can use script.aculo.us, etc.)

    function interpolate(source,target,pos) { return (source+(target-source)*pos); }
    function easing(pos) { return (-Math.cos(pos*Math.PI)/2) + 0.5; }
    
    function scrollToAnim(targetTop, duration) {
      duration || (duration = 1000);
      var start    = +new Date,
          finish   = start + duration,
          startTop = getScrollRoot().scrollTop,
          interval = setInterval(function(){
            var now = +new Date, 
                pos = (now>finish) ? 1 : (now-start)/duration;
            var y = interpolate(startTop, targetTop, easing(pos)) >> 0;
            window.scrollTo(0, y);
            if(now > finish) { 
              clearInterval(interval);
            }
          }, 10);
    }  
    

    get scroll root

    var getScrollRoot = (function() {
      var SCROLL_ROOT;
      return function() {
        if (!SCROLL_ROOT) {
          var bodyScrollTop  = document.body.scrollTop;
          var docElScrollTop = document.documentElement.scrollTop;
          window.scrollBy(0, 1);
          if (document.body.scrollTop != bodyScrollTop)
            (SCROLL_ROOT = document.body);
          else 
            (SCROLL_ROOT = document.documentElement);
          window.scrollBy(0, -1);
        }
        return SCROLL_ROOT;
      };
    })();