アンカーリンクまでをスムーススクロールさせたい時に調べて出てくる例のあのコード、ページ外や下層ページでは効かないんですよね。
今回は、固定ヘッダーの重なり対策済みの「全てを解決するコード」をご紹介します。
今回の記事では、以下の場合でスムーススクロールが可能となっています。
- ページ内リンク(example.com#sec1)
- 下層ページのページ内リンク(example.com/about#sec1)
- ページ外のアンカーリンク
jQueryで対応していますが、いずれJavaScriptで書けるようになったら追記します。
追記:JavaScriptの完全版をまとめました。

スムーススクロールでよく出てくるあのコード
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
の値は空の文字列(“”)になります。したがって、
chat.openai.comthis.hash === ""
は、this.hash
の値が空の文字列(“)に等しいかどうかをチェックします。つまり、href
属性が"#"
です。
つまり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デザイナーとなりました。
他にも様々なコースが充実しているので、身につけたいスキルがあったら是非覗いてみてください。
コースの一部をご紹介
コメント