OSSANS Project since 2020

「もし四十のおっさんがプログラミングを始めたらどう人生変わるのか」
このブログのメインテーマです
肩肘張らずにユルく、ときたま厳しくやっていきます
※プログラミング以外のことも書きます

JavaScript

2023.02.02(更新)

【CSSとJavaScriptのみ】ページ内リンクでスムーススクロールさせる方法

アイキャッチ画像
JavaScript

ページ内リンクをスムーススクロールさせたい!

今回はこんな要望に答えていきます。

本記事の内容

  • プラグインを使わず、CSSとJavaScriptだけでページ内リンクをスムーススクロールさせる方法

本記事を対象とする方

  • フロントエンドエンジニアを目指す方
  • Webデザイナーを目指す方

この記事を書いている僕はプログラミング歴2年5ヶ月です。webエンジニアとして”社内転職”に成功しました。

CSSとJavaScriptでの設定方法

まずはページ内リンクとは何かから説明します!

ページ内リンクとは、同じページ内の特定部分にジャンプ(移動)するリンクのことです。

ページ内リンク
※目次をクリック → 該当する見出しまでジャンプ!

aタグのhref属性には”#1″、ジャンプ先の特定部分にはid=”1″というように設定します。つまり、href属性の#(シャープ)以降の文字列と、特定部分のidの文字列を完全一致させることでページ内リンクをつくることができます。コンテンツの多いWebページには必須の動作だと言えるでしょう。

設定するファイルはHTMLだけです。ただし、HTMLだけでは一瞬でジャンプするのみでスムーススクロールの挙動が起こりません。スムーススクロールさせるにはCSSもしくはJavaScriptで設定する必要があります。

実際にどうやるのか。CSSから説明していきます。と言ってもCSSは説明するほどではありません。なぜなら一行で終わるからです。htmlタグに、scroll-behavior: smooth;を設定するだけです。

  1. html {
  2.   scroll-behavior: smooth;
  3. }

以上です。

あれ?あっさりしすぎじゃない?

なんだか簡単すぎて不安になるレベル…。

で、やはりその不安は的中。以下のような問題があり、あまりオススメできません。

  • Safariに対応していない
  • 全てのページ内リンクがスムーススクロールになる
  • 細かい調整ができないためスクロール位置がズレる
  • などなど

ですので、JavaScriptで設定するのが良いです。jQueryを使用する例はネットでたくさん検索ヒットするので、今回は生のJavaScriptのみを使用する場合で説明します。ちょっとだけ複雑になりますが、それでも難しいという内容ではありません。むしろ簡単な部類です。

ざっくりした内容は下記の通り。

  • 目次(aタグ)をクリック
  • 該当する見出し(h2)の位置を取得
  • scrollTo()メソッドで取得した見出しの位置までページをスクロール

コードは以下のようになります。

  1. function scrollToHeading() {
  2.   const a_all = document.querySelectorAll('a[href^="#"]');
  3.   a_all.forEach((a,index) => {
  4.     a.addEventListener('click', e => {
  5.       e.preventDefault();
  6.       
  7.       const h2_all = document.querySelectorAll('h2');
  8.       const h2_positionY = Math.floor(h2_all[index].getBoundingClientRect().top + window.scrollY);
  9.       
  10.       window.scrollTo({
  11.         behavior:'smooth',
  12.         top: h2_positionY,
  13.         left: 0,
  14.       });
  15.     });
  16.   });
  17. }
  18. window.addEventListener('DOMContentLoaded', () => {
  19.   scrollToHeading();
  20. });

以下、解説です。

  1. const a_all = document.querySelectorAll('a[href^="#"]');

href属性が‘#’で始まる全部のa要素を取得。

  1. a_all.forEach((a,index) => {
  2.   a.addEventListener('click', e => {
  3.     e.preventDefault();

取得した全部のa要素にクリックイベントを設定し、取得した全部のa要素にデフォルトで設定されているイベントを全て無効化

Point

e.preventDefault();とは?

直訳すると、「デフォルトの動作を妨げる」となります。

つまり、preventDefault();を設定すれば、デフォルトの動作を無効化することができます。

ではデフォルトの動作とは何か?それはユーザー側の動作で発動するイベントのことです。

クリック動作、キーダウン動作、マウス動作などがわかりやすい例でしょう。

例えばaタグは、クリックするとhref属性に設定されたidにジャンプするデフォルト動作がありますが、それを無効化することができます。

今回では一瞬でジャンプするのではなく、スムースにスクロールさせたいので、そういった動作が邪魔なわけです。ですから最初に無効化させておく必要があります。

eというのはeventの略でして、その要素が持つイベント動作ということになります。

  1. const h2_all = document.querySelectorAll('h2');
  2. const h2_positionY = Math.floor(h2_all[index].getBoundingClientRect().top + window.scrollY);

リンク先となるh2全てを取得。h2は配列になっていて、h2_all[index]とすることで、aのインデックスとh2のインデックスを同期できます。indexはいつ取得したのかというと、foreachを使った際、2番目の引数で取得しました。foreachは3番目まで引数を指定できるので、覚えておきましょう。そうして取得した全てのh2のページトップからのY座標をh2_positionYに入れておきます。

Point

Math.floorで小数点以下を切り捨て

getBoundingClientRect().top + window.scrollY);でh2のY座標を取得

  1. window.scrollTo({
  2.   behavior:'smooth',
  3.   top: h2_positionY,
  4.   left: 0,
  5. });

scrollToメソッドを使い、h2_positionYの位置(h2の位置)までスクロールするように設定。スクロールの振る舞いはスムースにしておく(behavior: smooth;の部分)。

  1. window.addEventListener('DOMContentLoaded', () => {
  2.   scrollToHeading();
  3. });

Webページには挿絵として画像リソースを入れる場合が多々あります。その際、そのリソースが読み込まれる前にブラウザがスクロールを始めると、ブラウザは画像の高さを計算せずにスクロールすることになるので位置がズレてしまいます。それを防ぐためにDOMContentLoadedで先にリソースが読み込んでおきます。デモページを作ったので、良かったら下記リンクからご覧ください。以上でJavaScriptでの設定は終了です。

スムーススクロールが効かないブラウザへの対応

スムーススクロールを設定したけど、あれ?効いてなくない?という方のために対応方法を解説します。

CSSのscroll-behaviorプロパティ、JavaScriptのscrollToメソッド。どちらも大変便利なのですが、ブラウザによってはサポートしていません。以下、サポート状況です。

scroll-behaviorサポート状況
※CSSのscroll-behaviorのサポート状況です
scrollToメソッドサポート状況
※JavaScriptのscrollToメソッドのサポート状況です behaviorはサポートされていません

Safariのサポート状況がイマイチなのが残念ですね。Safariがサポートされるまで待つ、というのも一つの手ですが、Polyfillを使えば解決できます。

Point

Polyfillとは、最近の機能をサポートしていない古いブラウザーで、その機能を使えるようにするためのコードです。大抵はウェブ上の JavaScript です。

Polyfill (ポリフィル) – MDN Web Docs 用語集

色々なPolyfillがありますので、ご自身で調べてみてください。今回はこちらのPolyfillをご紹介します。

https://www.npmjs.com/package/scroll-behavior-polyfill

npmかyarnを使ってダウンロードします。npmやyarnの説明は今回は割愛しますね。

このPolyfillの開発者の説明ではダウンロード後、JSファイルにimportするだけで良いとのことなんですが、importしても正常に動かなかったので、index.jsを直接読み込みました。すると、Safariでも動くようになりました。けど、Chromeと比較すると、スクロールスピードが微妙に違う…。まぁ、そのくらいは良しとしますかね…。

今回のまとめ

今回はページ内リンクでスムーススクロールさせる方法について紹介しました。最後まで読んで頂きありがとうございました。

CSSでもJavaScriptでも実装できる

JavaScriptでの実装のほうがおすすめ

サポートしていないブラウザ(特にSafari)では、Polyfillを使う

関連記事

  • JavaScript
    ブログアイキャッチ画像
    JavaScript
    2023.03.04(更新)

    【実例コードあり】覚えておきたいパララックスデザインの3つの基本

  • JavaScript
    ブログアイキャッチ画像
    JavaScript

    【ユーザー離脱阻止!】画面遷移アニメーション実装時の注意点

  • JavaScript
    ブログアイキャッチ画像
    JavaScript

    【図解あり】JavaScript / 要素の高さや位置の取得まとめ

  • JavaScript
    ブログアイキャッチ画像
    JavaScript
    2022.11.19(更新)

    「一瞬でトップへ戻るボタン」を実装する方法【jQuery不要】

  • JavaScript
    ブログアイキャッチ画像
    JavaScript
    2023.02.21(更新)

    【お手軽だった!】画像クリックで拡大画像をポップアップ表示する方法

  • JavaScript
    ブログアイキャッチ画像
    JavaScript
    2022.11.25(更新)

    【5分で完了!】webデザインにおけるスマホファーストビュー高さ設定方法

CATEGORY カテゴリー別最新記事

  • CSS
    アイキャッチ画像
    CSS

    【CSS】margin?position?要素の中央寄せで使うプロパティとは?

  • Docker
    アイキャッチ画像
    Docker
    2022.10.03(更新)

    【簡単設定!】DockerでWordPressをローカル開発する方法

  • HTML
    アイキャッチ画像
    HTML
    2023.02.18(更新)

    【図解あり】aタグの入れ子ルールとHTMLの入れ子ルールを覚える方法

  • JavaScript
    アイキャッチ画像
    JavaScript
    2023.03.04(更新)

    【実例コードあり】覚えておきたいパララックスデザインの3つの基本

  • Python
    アイキャッチ画像
    Python
    2023.02.09(更新)

    【やらなきゃ損!】2日でできるPythonのExcelコピペ自動化!

  • Study
    アイキャッチ画像
    Study
    2023.02.16(更新)

    稼ぐために始めたプログラミングのこれまでの振り返り。勉強方法や役立った本も紹介。

  • web site
    アイキャッチ画像
    web site
    2022.11.26(更新)

    ページ表示速度アップ!npmでソースファイルを軽量化する方法【サクッと簡単!】

  • WordPress
    アイキャッチ画像
    WordPress
    2022.10.26(更新)

    【コピペ可】WordPressサイトをPWA化するためにService Workerを実装してみた。