【jQuery】スムーススクロールの実装

#はじめに
スムーススクロールは、同じページ内を滑らかに移動させる機能のことです。
何か項目をクリックすると、画面がぬるっと動くというWebサイトをよく見かけると思いますが、まさにあの動きを実現するためのものです。
自分のWebサイトに実装する際、実際に触ってみて学んだことを整理しました。

#想定読者
・JavaScript、jQueryを学習中の方
・自作Webサイトに何か動きをつけたい方

#実現すること
スムーススクロールを実装し、ページが指定の場所に滑らかに移動するようにします。

#前提
純粋なJavaScriptやCSSだけでも実装する方法はありますが、今回はjQueryを使います。
jQueryの導入方法については、下記URLのサイトが分かりやすいかと思います。
本記事では「Google CDN」を活用しています。
「3.x snippet:」のscriptタグの記述を、そのままhtmlファイルにコピペすればOKです。

(参考)
https://creive.me/archives/19581/

#ソースコード・挙動
```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Scroll</title>
  <link rel="stylesheet" type="text/css" media="all" href="sample.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script type="text/javascript" src="scroll.js"></script>
</head>

<body>
  <h1 id="top">Top</h1>
  <ul>
    <li><a class="item" href="#first">First</a></li>
    <li><a class="item" href="#second">Second</a></li>
    <li><a class="item" href="#third">Third</a></li>
  </ul>
  <div id="first">
    <h2>First</h2>
  </div>
  <div id="second">
    <h2>Second</h2>
  </div>
  <div id="third">
    <h2>Third</h2>
  </div>
  <a class="backToTop" href="#top">Topに戻る</a>
</body>
</html>
```
```sample.css
/* スクロールの動きを確認するため、div要素に幅を持たせています */
div{
  height: 700px;
}

/* Topに戻るためのリンクを画面右下に固定しています */
.backToTop{
  position: fixed;
  right: 50px;
  bottom: 50px;
}
```
```scroll.js
$(function(){
  $('a[href^="#"]').click(function() { /* ①クリックアクションを設定 */
    var speed = 500; /* ②スクロールの速さを指定 */
    var href= $(this).attr('href'); /* ③クリックするリンクの位置の値を取得 */
    var target = $(href == "#" || href == "" ? 'html' : href); /* ④スクロール先を取得 */
    var position = target.offset().top; /* ⑤ページのトップからスクロール先までの位置を数値として取得 */
    $('body,html').animate({scrollTop: position}, speed, 'swing'); /* ⑥スクロールのアニメーション設定 */
    return false; /* ⑦falseを返し、URLに影響を与えないようにする */
  });
});
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="html,result" data-user="jnd_acgm" data-slug-hash="MWjKVyM" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="SmoothScroll">
  <span>See the Pen <a href="https://codepen.io/jnd_acgm/pen/MWjKVyM">
  SmoothScroll</a> by jnd_acgm (<a href="https://codepen.io/jnd_acgm">@jnd_acgm</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>


#解説
####①クリックアクションを設定
$('a[href^="#"]')
この記述は、「aタグのhref属性の値が#で始まるとき」ということを意味しています。
「^=」はjQueryのセレクタ指定方法の一つであり、前方一致を表します。
これにより、href属性で値が#から始まるすべての要素を取得することができます。

####②スクロールの速さを指定
var speed = 500;
変数speedにミリ秒単位でスクロールの速さを代入します。
この数値を変えることで、スクロールの速さを調整することが可能です。

####③クリックするリンクの位置の値を取得
var href= $(this).attr('href');
attrメソッドを使い、クリックするリンクの位置であるhref属性の値を取得し、変数hrefに代入します。

####④スクロール先を取得
var target = $(href == "#" || href == "" ? 'html' : href);
スクロール先を取得し、変数targetに代入します。
記述の意味としては、「変数hrefの値が#または空白であればhtml(リンク先指定箇所)、そうでなければhrefの値を変数targetに代入する」という内容になります。
論理演算子「||」や三項演算子「?」・「：」を使用し、簡潔に一行で表現しています。

####⑤ページのトップからスクロール先までの位置を数値として取得
var position = target.offset().top;
offsetメソッドを利用し、ページのトップからtargetまでの位置を取得し、変数positionに代入します。

####⑥スクロールのアニメーション設定
$('body,html').animate({scrollTop: position}, speed, 'swing');
animateメソッドを使用し、クリックするリンクからスクロール先までの動きを設定します。
{scrollTop: position}でpositionまでスクロールするという動き、speedで速さ、'swing'でスクロールの動き方を定めています。

####⑦falseを返し、URLに影響を与えないようにする
リンクをクリックすると、URLにIDタグが付与されてしまい正しく動作しないので、falseを返すことで防ぎます。

#まとめ
スムーススクロールはほとんどのWebサイトに実装されていると思いますが、ユーザーの使いやすさを考えると採用して損はないはずなので、ぜひ試してみて下さい！
少しでも参考になりましたら幸いです!

#参考情報
・jQuery導入方法
https://creive.me/archives/19581/

・スムーススクロール実装手順
https://changeup.tech/article/jquery-smooth-scroll/
https://techacademy.jp/magazine/9532

・JavaScriptリファレンス
(論理演算子)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_Operators
(三項演算子)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Conditional_Operator

・jQuery日本語リファレンス
(attrメソッド)
http://semooh.jp/jquery/api/attributes/attr/name/
(offsetメソッド)
http://semooh.jp/jquery/api/css/offset/_/