通常のページ内リンクは、クリックすると一瞬で移動されます。
この場合、ページ内を移動したことにユーザーが気づかないことがあるので、ちょっとした演出を加えることで同じページの中を移動したことをユーザーに伝えることができます。
その演出として、ページをゆっくりとした動きでスクロールさせて目的の位置へ移動させる「スムーススクロール」という方法があります。
今回は、jQueryを使ってスムーススクロールを実装してみましょう。
はじめに
このJavaScriptは、jQueryが読み込まれていることが前提で説明を行っています。
また、そのまま使用すると他のJavaScriptに干渉することがありますので、ご注意ください。
処理の流れ
スクリプトの関数で使用する変数を最初に宣言します。
ページ内リンクを設定するa要素を取得します。
取得したa要素にイベントリスナーを設定して、クリックイベントが発生したときに実行する関数を指定します。
クリックされたa要素からスクロールする先のページ位置を取得します。
目的の位置まで、スムーススクロールするアニメーションを実行します。
処理の説明
それでは、スムーススクロールを実装するための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プラグインにする書き方など、また改めてご紹介したいと思います。
コメント