公開日時:2022.05.22
最終更新日:2024/07/02
JavaScriptでスムーススクロールを実装しよう!
こんにちは!
Global Web Designの福田です。
みなさんスムーススクロールというのをご存知でしょうか?
ボタンをクリックしたりすると特定の場所まですーっとスクロールして表示してくれます。
「スムーススクロールを実装したいけどやり方がわからない…」
「jQueryを使わずにスムーススクロールを実装したい」
という方に向けて、スムーススクロールを実装していきたいと思います!
目次
スムーススクロールとは
まず最初にスムーススクロールとはどんなものでしょうか?
実装したものを見るとこういう動きになります。
See the Pen Untitled by Fukuda Yuzuru (@fukuda-yuzuru) on CodePen.
上のメニューを押すと各セクションにスムーズにスクロールしているのがわかるかと思います。
1番下にある「トップへ戻る」をクリックすると、1番上までスクールします。
スムーススクロールを実装するときの手順は
- HTMLにidを書いて該当の場所に移動させる
- JavaScriptでスムーズに移動させる
のようになります。
1つずつみていきたいと思います。
HTMLにidを書いて該当の場所に移動させる
まず最初にHTMLにidをつけてスクロールさせたい場所を決めます。
<body id="top"><!-- idを設定 -->
<header>
<nav>
<ul>
<li><a href="#1">セクション1へ</a></li><!-- hrefにスクロールさせたいidを書く -->
<li><a href="#2">セクション2へ</a></li><!-- hrefにスクロールさせたいidを書く -->
</ul>
</nav>
</header>
<main>
<div id="1"><!-- idを設定 -->
<p>セクション1</p>
</div>
<div id="2"><!-- idを設定 -->
<p>セクション2</p>
</div>
<a class="top" href="#top">トップへ戻る</a><!-- hrefにスクロールさせたいidを書く -->
</main>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script src="js/script.js"></script>
</body>
各セクションの親要素のdivタグに「id=”1″」「id=”2″」とidを書き、bodyタグに「id=”top”」
headerタグの中のaタグのhref属性にスクロールさせたいidを書きます。
今回は「<a href=”#1″>セクション1へ</a>」をクリックすると「id=”1″」の部分に移動。
「<a href=”#2″>セクション2へ</a>」をクリックすると「id=”2″」部分に移動。
「<a class=”top” href=”#top”>トップへ戻る</a>」をクリックすると先頭に移動します。
このままでも移動しますが、headerタグが「position: fixed;」で固定して浮いているので、「セクション1」「セクション2」という文字が、headerの下に潜ってしまいます。
またこのままでも移動はしますが、スムースに移動せずに瞬間的に移動してしまいます。
JavaScriptでスムーズに移動させる
ここから、JavaScriptを使って潜り込まない設定と、スムーススクロールの設定をJavascriptで行います。
var headerHeight = $('header').outerHeight();
$('a[href^="#"]').click(function() {
var href= $(this).attr("href");
var target = $(href);
var position = target.offset().top - headerHeight;
$('body,html').stop().animate({scrollTop:position}, 300);
return false;
});
変数を使ってheaderの高さを取得します。
2行目「a[href^=”#”]」で#からはじまるリンクをクリックした時の処理を書いていきます。
3行目「a[href^=”#”]」の「href」の値を「attr」を使って取得しています。
4行目 5行目3行目に取得した値を「target」という変数に格納します。
「var position = target.offset().top – headerHeight;」の「target.offset().top 」は「target」のスクロールの高さを取得し、「- headerHeight;」で浮いたheaderの高さをマイナスして潜り込ませないようにしています。
「animate」を利用しスムースにスクロールしています。
「animate({scrollTop:position}, 300);」の最後の「300」は「0.3秒」という意味ですので、「0.3秒」かけて「position」のトップに移動するということになります。
jQueryを使わないJavaScriptのコードはこちら。
See the Pen Untitled by Fukuda Yuzuru (@fukuda-yuzuru) on CodePen.
ページ外スクロール
先ほど、ご紹介したのは同じページ内へのスムーススクロールです。
では違うページにスムーススクロールをする場合どうなるでしょうか?
var headerHeight = $('header').outerHeight();
var url = location.hash;
if(url) {
$('body,html').stop().scrollTop(0);
setTimeout(function(){
var target = $(url);
var position = target.offset().top - headerHeight;
$('body,html').stop().animate({scrollTop:position}, 500);
}, 100);
}
$('a[href^="#"]').click(function() {
var href= $(this).attr("href");
var target = $(href);
var position = target.offset().top - headerHeight;
$('body,html').stop().animate({scrollTop:position}, 500);
});
「var
url = location.hash;
」でページ外からリンクしたときの、URLのハッシュを取得します。
ハッシュ(hash)とはURLの#以降の部分のことをいいます。
「https://global-web-design.com/727/#fixed」
で見ると#以降の「#fixed」が取得されます。
「if」を使ってページ外からのURLにハッシュがあった時の処理を書きます。
4行目ページ外からページ内のスクロールをするときに、直接ページ内のidの部分に移動してしまうので、直接移動しないように「$('body,html').stop().scrollTop(0);
」でスクロールをトップに戻します。
「setTimeout」を使って、0.1秒後にスクロールさせています。
ページの読み込みの処理が終わってからでないと正常にスクロールしないため、あえて遅らせてスクロールさせています。
jQueryを使わないJavaScriptのコードはこちら。
// スムーススクロール
// headerの高さを取得し、headeHeightに代入
const headerHeight = document.querySelector('header').offsetHeight;
//querySelectorAllメソッドを使用してページ内のhref属性が#で始まるものを選択
//forEachメソッドを使って、各アンカータグにクリックされた時の処理
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
// クリックされたときのデフォルトの挙動を防ぐ
e.preventDefault();
// クリックされたアンカータグのhref属性を取得
const href = anchor.getAttribute('href');
// href属性の#を取り除いた部分と一致するIDを取得
const target = document.getElementById(href.replace('#', ''));
//取得した要素の位置を取得するために、getBoundingClientRect()を呼び出し、ページ上の位置を計算。
//headerの高さを引いて、スクロール位置がヘッダーの下になるように調整します。
const targetPosition = target.getBoundingClientRect().top + window.scrollY - headerHeight;
// window.scrollTo()を呼び出して、スクロール位置を設定します。behaviorオプションをsmoothに設定することで、スムーズなスクロールを実現します。
window.scrollTo({
top: targetPosition,
behavior: 'smooth'
});
});
});
// ページ外スクロール
// ページが読み込まれたら処理を実行
window.addEventListener('DOMContentLoaded', function() {
// URLオブジェクトを使用して、現在のURLを解析し、ハッシュ値を取得
const url = new URL(location.href);
// slice()メソッドを使って、ハッシュ値の先頭の#を除去
const hash = url.hash.slice(1);
//取得したハッシュ値をIDとして持つ要素を取得
const target = document.getElementById(hash);
//targetに対応する要素が存在する場合、以下の処理を実行
if (target) {
//getBoundingClientRect()を呼び出して、スクロール先の要素の位置を取得。また、headerの高さを引いて、スクロール位置がヘッダーの下になるように調整
const top = target.getBoundingClientRect().top + window.scrollY - headerHeight;
//setTimeout()を使って、スクロール位置を初期化
setTimeout(function(){
window.scrollTo({top: 0}, 0);
});
//setTimeout()を使って、スクロール位置を設定します。この処理は、先程と同じ方法でスクロール位置を計算し、window.scrollTo()メソッドを呼び出して、スムーズなスクロールを実現
setTimeout(function(){
window.scrollTo({
top: top,
behavior: 'smooth'
});
});
}
});
jQueryよりもコードが長いですが、行なっている処理はほぼ同じです。
まとめ
いかがでしたでしょうか?
今回はスムーススクロールについてご紹介しました。
私自身、現在はjQueryは使用しておらずVue.jsというJavaScriptを使っています。
Vue.jsはもともとのJavaScriptでコードを書くため、スムーススクロールを実装するのに手こずりました。
忘備録として、もともとのJavaScriptのコードを書きましたが、jQueryを使いなれている方はjQueryでスムーススクロールを実装してみてください。
スムーススクロールもコードをいじれば好きなタイミングでのスクロールもできるので、コードをいじって自分好みにカスタマイズしていきましょう!
追記JavaScript forバージョン
上記のJavaScriptは「foreach」を使用して、スムーススクロールを行いましたが、「for」で作ったスムーススクロールもご紹介します。
JavaScriptの「for」での勉強、書き方をご覧になりたい方は見て勉強してみてください!