公開日時:2022.05.22

最終更新日:2023/08/05

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

マウス

こんにちは!
Global Web Designの福田です。

みなさんスムーススクロールというのをご存知でしょうか?
ボタンをクリックしたりすると特定の場所まですーっとスクロールして表示してくれます。

「スムーススクロールを実装したいけどやり方がわからない…」
「jQueryを使わずにスムーススクロールを実装したい」

という方に向けて、スムーススクロールを実装していきたいと思います!

スムーススクロールとは

まず最初にスムーススクロールとはどんなものでしょうか?
実装したものを見るとこういう動きになります。

See the Pen Untitled by Fukuda Yuzuru (@fukuda-yuzuru) on CodePen.

上のメニューを押すと各セクションにスムーズにスクロールしているのがわかるかと思います。
1番下にある「トップへ戻る」をクリックすると、1番上までスクールします。

スムーススクロールを実装するときの手順は

  1. HTMLにidを書いて該当の場所に移動させる
  2. 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;
});
1行目

変数を使って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の高さをマイナスして潜り込ませないようにしています。

6行目

「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);   
});
2行目

var url = location.hash;」でページ外からリンクしたときの、URLのハッシュを取得します。
ハッシュ(hash)とはURLの#以降の部分のことをいいます。
「https://global-web-design.com/727/#fixed」
で見ると#以降の「#fixed」が取得されます。

3行目

「if」を使ってページ外からのURLにハッシュがあった時の処理を書きます。

4行目

ページ外からページ内のスクロールをするときに、直接ページ内のidの部分に移動してしまうので、直接移動しないように「$('body,html').stop().scrollTop(0);」でスクロールをトップに戻します。

5行目

「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よりもコードが長いですが、行なっている処理はほぼ同じです。

Safariでスムーススクロールが動かない場合

JavaScriptの

behavior: 'smooth'  // スクロールアニメーション

とCSSの

html {
  scroll-behavior: smooth;
}

はSafariだと上手くスムーススクロールできません。
Safariでスクロールの「smooth」が効かない場合は、Polyfillを使うと動くようになります。

まずPolyfillのサイトに移動します。
https://polyfill.io/v3/

Polyfillのメニューの「CREATE A POLYFILL BUNDLE」をクリックします。

「CREATE A POLYFILL BUNDLE」のページに入ったら、「Filter Polyfills」に「scroll」と入力します。
「Available Polyfills」の中の「smoothscroll」をチェックして、URL HTMLのコードをbody閉じタグの直前に入れます。

<script src="https://polyfill.io/v3/polyfill.min.js?features=smoothscroll"></script>

これでSafariでもスムーススクロールが動きます。

まとめ

いかがでしたでしょうか?
今回はスムーススクロールについてご紹介しました。

私自身、現在はjQueryは使用しておらずVue.jsというJavaScriptを使っています。

Vue.jsはもともとのJavaScriptでコードを書くため、スムーススクロールを実装するのに手こずりました。
忘備録として、もともとのJavaScriptのコードを書きましたが、jQueryを使いなれている方はjQueryでスムーススクロールを実装してみてください。
スムーススクロールもコードをいじれば好きなタイミングでのスクロールもできるので、コードをいじって自分好みにカスタマイズしていきましょう!

この記事を書いた人
福田 弦

福田 弦

2020年にGlobal Web Desingを立ち上げ。得意分野は、コーディング、CMS構築、ディレクション。現在はブログ、マーケティングなどを勉強中。趣味はドラム。

追記JavaScript forバージョン

上記のJavaScriptは「foreach」を使用して、スムーススクロールを行いましたが、「for」で作ったスムーススクロールもご紹介します。

JavaScriptの「for」での勉強、書き方をご覧になりたい方は見て勉強してみてください!

SNSでシェア