JavaScript

ページ上部やページ内へのリンクをスクロールさせる

jQueryを使って、ページの上へ戻るボタンやページ内リンクをスクロールさせる方法です。基本的には簡単です。

準備

ページ内の特定の場所へ移動するリンクは、移動先のHTML要素にid属性を設定します。リンク元のhref属性には#(フラグメント識別子)に続くid属性を指定します。

<body id="page-top">
〜
〜
<a href="#page-top">上へ戻る</a>
</body>

以前のHTMLで使われていたname属性でも機能することがありますが、現代のHTMLではid属性を使用するのが正しいです。他のURLの特定の場所へのリンクの場合は、URLに続けて#idを指定します。

<a href="./location/#accessmap" target="_blank">当社アクセスマップ</a>

jQuery

簡単な例。href属性が#から始まるa要素にクリックのイベントリスナを設けます。例では何もしてないですが、必要なら適宜e.preventDefault()とかstopPropagation()とかでイベント伝播の処理も追加します。

$(document).ready(function() {

  $('a[href^="#"]').on('click', function(e){
    var href = $(this).attr('href');
    if (!window.$page) window.$page = $('body, html');
    $page.animate(
      { 'scrollTop': ( href == '#' ? $page: $(href) ).offset().top },
      { 'duration': 500, 'easing': 'swing' }
    );
    return false;
  });

});

スクロールさせるためにreturn false;で本来の動作をキャンセルしているので、クリックしてもアドレスバーが更新されなくなります。履歴が必要な場合は非同期(jQuery AJAX)でページ移動した時の履歴とかのメモで書いたような方法で履歴の操作をする必要が出てくると思います。

$('body, html')をわざわざwindow.$pageに代入しているのは、クリックイベントが発生するたびに$('body, html')のパースをさせないためです。別になくてもいいですが無駄な処理は極力なくした方がいいと思います。'body'でもいいところを'body, html'としているのは旧バージョンのSafariかなんかの対策です(詳細忘)。

animate()で指定しているscrollTopの値は、offset().topを得るセレクタを条件分岐させています。href="#"の場合は、ページの一番上に戻れるよう$pageが入ります。

animate()scrollLeftの値を指定すれば左右のスクロールもできます。イージングによっては上下左右を同時にスクロールすると変な動きになるかもしれません。

#IDの付いたURLで、最初にスクロールさせる

URLの後に#ID(フラグメント識別子)のついたページをスクロールさせて表示する方法です。

#IDのついたURLは、アドレスバーを確認でもしない限り、ぱっと見て「ページの途中」であることがわかりにくいこともあります。通常どおりページ最上部を表示した後でスクロールしてから該当箇所へ移動することで、ページの途中へやってきたことがわかりやすくなります。

フラグメント識別子はJavaScriptlocation.hashで取得します。流れとしては、location.hashを保存した後、一度location.hashのないURLへ書き換えし、ページが表示されてからスクロールします。

スクロールするテスト

var hash = (location.hash && location.hash != '#') ? location.hash: null;

// アドレスバーを書き換える(履歴を追加する)
if (hash) {
  window.history.pushState(null, null, location.href.replace(hash, '') );
}


// ロード後処理
$(window).on('load', function() {
  // ID属性を持つ要素がある場合のみスクロール実行
  if (hash && $(hash).size()) {
    // 500ミリ秒後にスクロール
    $('body, html').delay(500).animate(
      {
        'scrollTop': $(hash).offset().top,
        'scrollLeft': $(hash).offset().left
      },
      { 'duration': 500, 'easing': 'swing' }
    );
  }
});

URLに#IDが付いたままだと最初にページ最上部の表示にならないのでhistory.pushState()のところで、URLを識別子がないものに書き換えています。最初にページトップへ強制的に移動しておくでもいいですしlocation.href#以降がないURLへ移動しておくのでもいいですし、方法はどうでもいいですがとにかく最初にページ最上部を表示しておくようにしています。

で、$(document).ready()ではなく、ページ読み込みが完了してからスクロールさせるようにしています。このほうが表示済みコンテンツが揃っていてスクロールがスムーズかなと思います。


以上、jQueryを使ってページ上部やページ内リンクをスクロールさせる一例でした。他にも方法あると思いますがどなたかの参考にでもなれば書いた甲斐があるというもので幸いでございます。