要素のスクロール時に処理を行う方法

スクロール位置の取得

element.onscroll = function()
{
    // スクロールされたピクセル数
    var scroll = this.scrollTop;

    // スクロール範囲の最大のピクセル数
    var range = this.scrollHeight - this.offsetHeight;
}
スクロールされた位置  
スクロール範囲の最大値  
スクロールした割合  
    ※リストの数値は、親要素からのオフセット

    ドキュメントのスクロール位置

    ドキュメントがスクロールされた位置 (scrollTop) を取得するとき、ブラウザによってそれを返すオブジェクトが異なります。よって次のように、2つのオブジェクトから取得するようにします。

    window.onscroll = function()
    {
        var scrollTop =
            document.documentElement.scrollTop || // IE、Firefox、Opera
            document.body.scrollTop;              // Chrome、Safari
    }
    

    ただしこれらのオブジェクトは、

    • document.documentElement … html要素 (Document.documentElement)
    • document.body … body要素 (HTMLDocument.body)

    のように異なる要素を参照するため、異なる値を返すことがあります。この違いはドキュメントのサイズとスクロール位置を確認するページで確認できます。

    ところでこのscrollTopに値を設定すればドキュメントをスクロールできますが、Windowオブジェクトにはそれ専用のメソッドが用意されています。

    スクロールに応じた処理

    下端までスクロールされたら、末尾に要素を追加

    表示領域の下端までスクロールされたときに、末尾に要素を追加します。初期状態では最小限の表示だけを行い、必要になった時点で要素を追加することで、パフォーマンスの向上を見込めます。

    <div id="box" style="height: 100px; overflow: auto"></div>
    
    <script type="text/javascript">
      var box = document.getElementById( 'box' );
      var lastElement = box.appendChild( document.createElement( 'div' ) );
    
      box.onscroll = function()
      {
          // 表示領域の下端の位置
          var bottom = this.scrollTop + this.clientHeight;
    
          // 末尾の要素の上端の位置
          var top = lastElement.offsetTop - this.offsetTop;
    
          if( top < bottom )
          {
              var div = document.createElement( 'div' );
              this.appendChild( div );
    
              // 追加した要素を最後の要素とする
              lastElement = div;
          }
      }
    </script>
    
    表示領域の下端の位置  
    末尾の要素の上端の位置  
      ※リストの数値は、親要素からのオフセット

      要素が見える範囲に入ったら、その要素の処理を実行 (遅延読み込み)

      スクロールによって要素が可視範囲に入ってから、その要素の処理を実行します。これは処理に時間のかかる要素、たとえばファイルサイズの大きな画像などの読み込みを遅延させることで、ページ全体のパフォーマンスを向上させるような用途に有効です。

      <div id="box" style="height: 100px; overflow: auto"></div>
      
      <script type="text/javascript">
          function DelayLoad( box, elem, callback )
          {
              var CheckVisibility = function()
              {
                  // 表示領域の下端の位置
                  var bottom = box.scrollTop + box.clientHeight;
      
                  // 要素の上端の位置
                  var top = elem.offsetTop - box.offsetTop;
      
                  if( top < bottom )
                  {
                      // イベントハンドラを削除する
                      if( box.removeEventListener )
                      {
                          box.removeEventListener( 'scroll', CheckVisibility, false );
                      }
                      else if( box.detachEvent )
                      {
                          box.detachEvent( 'onscroll', CheckVisibility );
                      }
      
                      // コールバックを呼び出す
                      callback( elem );
                  }
              }
      
              // scrollに応答して要素の状態を調べるように、ハンドラを登録する
              // Internet Explorer 9より前をサポートしないならば、addEventListenerだけで十分
              if( box.addEventListener )
              {
                  box.addEventListener( 'scroll', CheckVisibility, false );
      
                  // ドキュメントの構築を待ってから初期化する
                  window.setTimeout( CheckVisibility, 0 );
              }
              else if( box.attachEvent )
              {
                  box.attachEvent( 'onscroll', CheckVisibility );
                  window.setTimeout( CheckVisibility, 0 );
              }
              else
              {
                  callback( elem );
              }
          }
      
          //
          var box = document.getElementById( 'box' );
      
          var list = document.createElement( 'ol' );
          box.appendChild( list );
      
          for( var i = 0; i < 100; i++ )
          {
              var li = document.createElement( 'li' );
              list.appendChild( li );
      
              // 各要素の状態監視と、コールバックの登録
              DelayLoad( box, li, function( elem )
                  {
                      // 1000ミリ秒後に、渡された要素内に'ok'と表示
                      window.setTimeout( function() { elem.innerHTML = 'ok'; }, 1000 );
                  } );
          }
      </script>
      

      可視範囲に入った後、1秒後に[ok]と表示します。

      遅延読み込みを実現する方法として、jQueryのプラグインであるLazy Loadを使用する方法もあります。

      ドキュメント内でスクロールする場合

      スクロール範囲が要素内ではなくドキュメント内であるならば、ウィンドウの表示領域の大きさを基準とします。

      var targetElement; // 対象とする要素
      
      window.onscroll = function()
      {
          var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
      
          // ウィンドウのビューポートの下端の位置
          var bottom = scrollTop + document.documentElement.clientHeight;
      
          // 対象とする要素の上端の位置
          var top = targetElement.offsetTop;
      
          if( top < bottom )
          {
              // 可視範囲に入ったときの処理
          }
      }
      
      JavaScriptのドキュメントから検索