スムーススクロールを実装しよう

通常のページ内リンクは、クリックすると一瞬で移動されます。
この場合、ページ内を移動したことにユーザーが気づかないことがあるので、ちょっとした演出を加えることで同じページの中を移動したことをユーザーに伝えることができます。

Webページのスクリーンキャプチャー
画像をクリックすると、ページ内を一瞬で移動している様子が見られます

その演出として、ページをゆっくりとした動きでスクロールさせて目的の位置へ移動させる「スムーススクロール」という方法があります。

Webページのスクリーンキャプチャー
画像をクリックすると、スクロールして移動している様子が見られます
※アニメーションGIF形式に変換しているため、動きがカクカクしています

今回は、jQueryを使ってスムーススクロールを実装してみましょう。

目次

はじめに

このJavaScriptは、jQueryが読み込まれていることが前提で説明を行っています。

また、そのまま使用すると他のJavaScriptに干渉することがありますので、ご注意ください。

処理の流れ

STEP
変数の宣言

スクリプトの関数で使用する変数を最初に宣言します。

STEP
対象となる要素を取得

ページ内リンクを設定するa要素を取得します。

STEP
イベントリスナーを設定して、クリックしたときに処理を行う

取得したa要素にイベントリスナーを設定して、クリックイベントが発生したときに実行する関数を指定します。

STEP
スクロールする先の位置を取得

クリックされたa要素からスクロールする先のページ位置を取得します。

STEP
スムーススクロールのアニメーションを実行

目的の位置まで、スムーススクロールするアニメーションを実行します。

処理の説明

それでは、スムーススクロールを実装するためのJavaScriptを、ステップごとに説明していきます。

STEP1 変数の宣言

最初に関数で使う予定の変数を宣言します。

var $link;
var href;
var target;
var position;

STEP2 対象となる要素を取得

スムーススクロールさせるリンクをjQueryで取得します。
ここでは、グローバルナビゲーションにあるメニューのリンクを対象として説明します。

HTMLは以下のようになっているものとします。

<nav id="gNav">
  <ul>
   <li><a href="#page01">メニュー1</a></li>
   <li><a href="#page02">メニュー2</a></li>
   <li><a href="#page03">メニュー3</a></li>
  </ul>
</nav>

id属性「gNav」を目印として、jQueryで要素を取得します。

$link = $('#gNav').find('a');

変数「$link」に、nav要素の中にあるa要素が格納されます。

STEP3 イベントリスナーを設定して、クリックしたときに処理を行う

変数「$link」に格納されたa要素にイベントリスナーを設定して、クリックイベントを検知すると、処理が実行されるようにします。

$link.on('click', function () {
  //ここに処理を書く
});

STEP4 スクロールする先の位置を取得

スクロールする先がページのどの位置にあるか、取得します。

href属性から、リンク先のid属性を取得

まず、クリックされたリンク(a要素)のhref属性に設定された値から、リンク先のid属性を抜き出して、変数「href」へ格納します。

$link.on('click', function () {

  // href属性から、リンク先のid属性を取得
  href = $(this).attr('href').replace(/.*(#.*)/g, '$1');

});
href属性の値を取得

クリックされたa要素は「this」に格納されていますから、jQueryで処理できるように「$()」で囲みます。
続いて、jQueryのメソッド「attr()」を使って、href属性を取得します。

値を加工して、変数へ格納

JavaScriptのメソッド「replace()」を使って、「#」以後のテキストを取得して、変数「href」へ格納します。

// この場合は、変数hrefに「#page01」が格納されます。
<a href="#page01">メニュー1</a>

// この場合は、変数hrefに「#news」が格納されます。
<a href="https://tech-blog.tomono.jp/index.html#news">お知らせ</a>

移動先を取得

取得したid属性からリンク先の要素を取得して、変数「target」へ格納します。

$link.on('click', function () {

  // href属性から、リンク先のid属性を取得
  href = $(this).attr('href').replace(/.*(#.*)/g, '$1');

  // 移動先を取得
  if ( href === '#' || href === '' ) {
    target = $('html');
  } else {
    target = $(href);
  }
});
ページ内リンクでない場合は、html要素を取得

メニューはナビゲーションには、ページ内リンクでない場合もあります。
また、ページトップのようにページの先頭へ移動するためのリンクが設定される場合もあります。

そのため、if文で変数「href」の値が、「#」のみ、または空白の場合はhtml要素を取得します。

ページ内リンクの場合は、id属性を目印に要素を取得

jQueryで、変数「href」と同じ値のid属性を持つ要素を取得します。

移動先の位置を取得

jQueryのメソッド「offset()」を使って、移動先のページ位置を取得して、変数「position」に格納します。

$link.on('click', function () {

  // href属性から、リンク先のid属性を取得
  href = $(this).attr('href').replace(/.*(#.*)/g, '$1');

  // 移動先を取得
  if ( href === '#' || href === '' ) {
    target = $('html');
  } else {
    target = $(href);
  }

  // 移動先の位置を取得
  position = target.offset().top;

});

STEP5 スムーススクロールのアニメーションを実行

jQueryのメソッド「animate()」を使って、アニメーションしながら移動先までスクロールします。

$link.on('click', function () {

  // href属性から、リンク先のid属性を取得
  href = $(this).attr('href').replace(/.*(#.*)/g, '$1');

  // 移動先を取得
  if ( href === '#' || href === '' ) {
    target = $('html');
  } else {
    target = $(href);
  }

  // 移動先の位置を取得
  position = target.offset().top;

  // アニメーションを実行
  $('body, html').animate({scrollTop: position}, 800, 'swing');
});
body要素、html要素をjQueryで取得

まず、html要素とbody要素をjQueryで取得します。

jQueryのメソッド「scrollTop()」がブラウザよって、html要素とbody要素のどちらかでしか動作しない事情があるため、両方を取得しています。
そのため、コールバックで何かしらの処理を行う場合は2回実行されることになりますので、注意してください。

取得した要素に対してメソッド「animate()」を設定

アニメーションメソッドのanimate()を設定します。

$('body, html').animate(
  {scrollTop: position},  //引数:properties
  800,                    //引数:duration
  'swing'                 //引数:easing
);

引数「properties」に「scrollTop: position」を指定して、移動先の位置までスクロールするように設定します。

引数「duration」にアニメーションが完了するまでの時間を設定します。

引数「easing」にイージング(動きの加減速)を設定します。

a要素の動作の無効化

a要素はリンクとして動作するため、このままではアニメーション終了後に、リンク本来の動作が始まってしまいます。

a要素の動作を無効化するため、最後に以下のコードを記述します。

return false;

まとめ

完成したJavaScriptのコードは以下のようになります。

var $link;
var href;
var target;
var position;

$link = $('#gNav').find('a');

$link.on('click', function () {
  href = $(this).attr('href').replace(/.*(#.*)/g, '$1');
  if ( href === '#' || href === '' ) {
    target = $('html');
  } else {
    target = $(href);
  }
  position = target.offset().top;
  $('body, html').animate({scrollTop: position}, 800, 'swing');
  return false;
});

処理の流れを説明するため、一部冗長な書き方をしているところがあります。
また、他のJavaScriptに配慮していない書き方なので、このまま使用するとエラーが発生することがあります。

グローバル汚染をしないような書き方や、jQueryプラグインにする書き方など、また改めてご紹介したいと思います。

よかったらシェアしてね!

この記事を書いた人

Webコーダーとして日々研鑽しています。
最近はJavaScriptで実現できるギミックが増えることに喜びながら、後方互換に悩むのが日課になっています。

コメント

コメントする

目次
閉じる