【jQuery】全てのページのリンクに対応したスムーススクロール

【jQuery】全てのページのリンクに対応したスムーススクロール

アンカーリンクまでをスムーススクロールさせたい時に調べて出てくる例のあのコード、ページ外や下層ページでは効かないんですよね。

今回は、固定ヘッダーの重なり対策済みの「全てを解決するコード」をご紹介します。

今回の記事では、以下の場合でスムーススクロールが可能となっています。

  • ページ内リンク(example.com#sec1)
  • 下層ページのページ内リンク(example.com/about#sec1)
  • ページ外のアンカーリンク

jQueryで対応していますが、いずれJavaScriptで書けるようになったら追記します。

追記:JavaScriptの完全版をまとめました。

WordPressのおすすめサーバー

特徴
  • 料金が安い
  • WordPressが超高速
  • ドメイン永久無料
  • 安心の実績とサポート体制

新規も乗り換えも

目次

スムーススクロールでよく出てくるあのコード

jQuery('a[href^="#"]').click(function() {
  let header = jQuery("header").innerHeight();
  let speed = 300;
  let href = jQuery(this).attr("href");
  let target = jQuery(href == "#" || href == "" ? "html" : href);
  let position = jQuery(target).offset().top - header;
  jQuery("html, body").animate(
    {
      scrollTop: position
    },
    speed
  );
  return false;
});

スムーススクロールで検索した時、おおよそ同じようなコードが出るのではないでしょうか。

このコードの問題点

[href^=”#”]は、#から始まるリンク要素しか当てはまらないため、#より前にある文字がある場合は使えません。

  • href=”/about#section1″
  • href=”example.com/about#section1″
  • href=”#section1″

つまりトップページでしか使えないということです。

全てを解決するコード

// スムーススクロール

// 固定ヘッダーの高さ(+追加したい余白)
var headerHeight = jQuery('header').outerHeight() + 20;

// ページ内のアンカーへスクロール
jQuery('a[href*="#"]').click(function () {
  var target = jQuery(this.hash === '' ? 'html' : this.hash);
  var position = target.offset().top - headerHeight;
  if (target.length) {
    jQuery('html, body').animate({scrollTop:position}, 500, 'swing');

    // #タグをURLに残す場合は削除
    return false;
  }
});

// ページ外のアンカーへスクロール
var urlHash = location.hash;
if(urlHash) {
  var target = jQuery(urlHash);
  var position = target.offset().top - headerHeight;
  // どこからスクロールさせるか ※一番上ならscrollTop(0)
  jQuery('body,html').stop().scrollTop(position - 200);
  setTimeout(function(){
    jQuery('body,html').stop().animate({scrollTop:position}, 500, 'swing');
  }, 100);
}

出来るだけ短く簡潔にしてみました。

解説をつけたバージョンも貼っておきます。

// スムーススクロール

// 固定ヘッダーの高さ(+追加したい余白)
var headerHeight = jQuery('header').outerHeight() + 20;

// ページ内のアンカーへスクロール
// #を含むa要素をクリックした時
jQuery('a[href*="#"]').click(function () {
  // リンク先を指定(href="#"ならばhtml、そうでなければ指定したアンカーを代入)
  var target = jQuery(this.hash === '' ? 'html' : this.hash);
  // リンク先の位置から固定ヘッダー分の高さを引く(重なり防止)
  var position = target.offset().top - headerHeight;
  // リンク先が存在する時
  if (target.length) {
    // スクロール実行(500ミリ秒、swingの動きを指定)
    jQuery('html, body').animate({scrollTop:position}, 500, 'swing');

    // #タグをURLに残す場合は削除
    return false;
  }
});

// ページ外のアンカーへスクロール
// URLのアンカー(#以降の部分)を取得
var urlHash = location.hash;
// URLのアンカーが存在する時
if(urlHash) {
  // リンク先をURLのアンカーに指定
  var target = jQuery(urlHash);
  // リンク先の位置から固定ヘッダー分の高さを引く(重なり防止)
  var position = target.offset().top - headerHeight;
  // どこからスクロールさせるか ※一番上ならscrollTop(0)
  jQuery('body,html').stop().scrollTop(position - 200);
  // ロード時の処理を待ち、時間差でスクロール実行(100ミリ秒)
  setTimeout(function(){
    // スクロール実行(500ミリ秒、swingの動きを指定)
    jQuery('body,html').stop().animate({scrollTop:position}, 500, 'swing');
  }, 100);
}
補足

$ を使わず jQueryとしているのは、WordPressでは動かないためです。

対処法として$ を jQueryに置き換えるか、おまじない$(function() {});ではなくjQuery(function($){}); で囲むようにすれば動きます。

どちらでも構いませんが、コピペして動かない!を防ぐためにあらかじめ jQueryで記述しています。

コードを解説

共通の固定ヘッダー

共通で使用する固定ヘッダーの高さは、headerHeightに代入しています。
ヘッダーと飛んだ先がピッタリくっついてしまうと見にくいので+20pxの余白を持たせました。

もし固定ヘッダーにしない場合は、高さを0にするか、headerHeightの記述を全て削除すればOKです。

ページ内のアンカーへスクロール

ページ内のスクロールのみ必要な方は、こちらのコードをコピペでそのまま使えます。

// 固定ヘッダーの高さ(+追加したい余白)
var headerHeight = jQuery('header').outerHeight() + 20;

// ページ内のアンカーへスクロール
// #を含むa要素をクリックした時
jQuery('a[href*="#"]').click(function () {
  // リンク先を指定(href="#"ならばhtml、そうでなければ指定したアンカーを代入)
  var target = jQuery(this.hash === '' ? 'html' : this.hash);
  // リンク先の位置から固定ヘッダー分の高さを引く(重なり防止)
  var position = target.offset().top - headerHeight;
  // リンク先が存在する時
  if (target.length) {
    // スクロール実行(500ミリ秒、swingの動きを指定)
    jQuery('html, body').animate({scrollTop:position}, 500, 'swing');

    // #タグをURLに残す場合は削除
    return false;
  }
});

実はこのコード、AIであるChatGPTでヒントを得ながら作りました。

よく出回っているコードとの違いは、以下の2つです。

a[href^="#"]
↓
a[href*="#"]

jQuery(href == "#" || href == "" ? "html" : href);
↓
jQuery(this.hash === '' ? 'html' : this.hash);

1つ目、href*="#"では#を含む場合となるので、hrefのどこかに#が入っていれば実行されます。

2つ目、href値が空の文字列("#"に等しい場合)ならばhtml、そうでない場合はthis.hashがリンク先となります。

this.hashは、#以降を取得します。

これでhrefのどこに#があっても、ターゲット先にスムーススクロールしてくれるようになります。

なぜthis.hash === “”で”#”扱いになるのか

<a href=”#”>の場合、this.hash === '#' ではなくthis.hash === ''が同じ扱いになるようです。

よく分からなかったのでChatGPTで聞いてみました。

this.hashの値は、#記号に続くリンク要素のhref属性の部分です。

たとえば、リンク要素のhref属性が"#example"の場合、this.hashの値は"#example"になります。href属性が"#"の場合、this.hashの値は空の文字列(“”)になります。

したがって、this.hash === ""は、this.hashの値が空の文字列(“)に等しいかどうかをチェックします。つまり、href属性が"#"です。

chat.openai.com

つまりhref属性が”#”の場合、this.hashの値は空の文字列(“”)になる

ChatGPTすごい。

書き換えの応用

href="#"の場合はスクロールさせたくない

var target = this.hash;

href="#top"の場合にのみ上にスクロールさせたい

var target = jQuery(this.hash === '#top' ? 'html' : this.hash);

ページ外のアンカーへスクロール

// 固定ヘッダーの高さ(+追加したい余白)
var headerHeight = jQuery('header').outerHeight() + 20;

// ページ外のアンカーへスクロール
// URLのアンカー(#以降の部分)を取得
var urlHash = location.hash;
// URLのアンカーが存在する時
if(urlHash) {
  // リンク先をURLのアンカーに指定
  var target = jQuery(urlHash);
  // リンク先の位置から固定ヘッダー分の高さを引く(重なり防止)
  var position = target.offset().top - headerHeight;
  // どこからスクロールさせるか ※一番上ならscrollTop(0)
  jQuery('body,html').stop().scrollTop(position - 200);
  // ロード時の処理を待ち、時間差でスクロール実行(100ミリ秒)
  setTimeout(function(){
    // スクロール実行(500ミリ秒、swingの動きを指定)
    jQuery('body,html').stop().animate({scrollTop:position}, 500, 'swing');
  }, 100);
}

こちらもググったものを簡潔にしたもので、このままコピペで使えます。

どこからスクロールさせるかは好みの問題ですが、ページが移動した際に一番上からスクロールすると騒がしいので移動先の200px上からに指定しています。

また、ページロードの処理を待ってからでないと正常にスクロールできませんのでsetTimeout(function()で100ミリ秒後にスクロールさせています。

必要に応じて各数値を変更してください。

まとめ:全てのページにスムーススクロールを

以上、簡潔簡単にスムーススクロールする方法を解説しました。

脱jQueryを目指し、Vanilla JS(JavaScript)で書けるようになったら改めて記事にしたいと思います。

よかったらブックマークなどをしてご自身でも挑戦してみてください。

カスタマイズを自分でしてみませんか?

「あの機能追加したいな」「もう少しここを調整したいな」と思ったらWeb制作のスクール「デイトラ」がおすすめです…!

カリキュラムは3ヶ月分ですが、受講生は卒業後もずっと見放題!常に最新のコンテンツに更新されるため、情報が古くなるなんてこともありません。

価格はどのコースも10万円前後と他のスクールに比べても格安です。
なのに副業・転職に十分なスキルが身につきます。

管理人

私はWeb制作とWebデザインを受講し、現在フリーランスWebデザイナーとなりました。

他にも様々なコースが充実しているので、身につけたいスキルがあったら是非覗いてみてください。

コースの一部をご紹介

よかったらシェアしてね!

コメント

コメントする

目次