固定ヘッダーの高さを考慮したスムーススクロール|jQueryでページ内リンクを調整する方法

Webサイトでは、ページ内のリンクをクリックしたときに、指定したセクションまで滑らかにスクロールする「スムーススクロール」がよく使われます。

例えば、

  • 「詳しく見る」をクリックして該当セクションへ移動する
  • ページ上部のメニューから各セクションへ移動する
  • 「お問い合わせ」ボタンからお問い合わせフォームへ移動する
  • 目次からページ内の見出しへ移動する

といった場面で利用できます。

しかし、ヘッダーを画面上部に固定しているWebサイトでは、通常のスムーススクロールを実装すると、スクロール先のコンテンツが固定ヘッダーの下に隠れてしまうことがあります。

そこで今回は、jQueryを使って固定表示しているヘッダーの高さを取得し、その高さを考慮してスクロール位置を調整する方法を紹介します。

目次

固定ヘッダーがあるとコンテンツが隠れてしまう

まず、一般的なページ内リンクでは、以下のようにidを指定してリンク先を設定します。

<a href="#about">詳しく見る</a>

<section id="about">
  <h2>About</h2>
  <p>ここがスクロール先です。</p>
</section>

この状態で#aboutへスムーススクロールさせると、基本的にはid="about"が付いている要素の位置までスクロールします。

しかし、例えばヘッダーが、

header {
  position: fixed;
  top: 0;
}

のように固定表示されている場合、スクロール後にヘッダーとコンテンツが重なってしまうことがあります。

そこで、スクロール先の位置からヘッダーの高さ分だけ上へ移動させることで、この問題を解決します。

ヘッダーの高さを考慮したスムーススクロール

今回使用するjQueryのコードはこちらです。

jQuery(document).ready(function() {
  // <header>の高さを取得
  const headerHeight = $('header').outerHeight();

  // ページ内スクロール
  $('a[href^="#"]').click(function () {
    const speed = 600;
    let href = $(this).attr("href");
    let target = $(href == "#" || href == "" ? "html" : href);

    // スクロール先の位置を取得し、<header>の高さを考慮して補正
    let position = target.offset().top - headerHeight;

    $("body,html").animate({ scrollTop: position }, speed, "swing");
    return false;
  });
});

このコードでは、

  1. ヘッダーの高さを取得する
  2. ページ内リンクがクリックされたことを検出する
  3. リンク先の位置を取得する
  4. ヘッダーの高さを引いてスクロール位置を補正する
  5. 指定した位置まで滑らかにスクロールする

という処理を行っています。

jQueryを読み込んでいることを確認する

今回のコードはjQueryを使用しているため、サイトでjQueryが利用できる状態になっている必要があります。

WordPressではテーマやプラグインなどによってjQueryが読み込まれているケースもありますが、使用している環境によって異なります。

ブラウザのコンソールに、

$ is not defined

などのエラーが表示される場合は、jQueryが正しく読み込まれているか確認してください。

ドキュメントの読み込み完了後に処理する

最初の部分では、

jQuery(document).ready(function() {

と記述しています。

これは、HTMLのDOMが読み込まれた後にJavaScriptを実行するための記述です。

ページ内のHTML要素が存在する状態になってから処理を実行することで、ヘッダーやリンクなどの要素を正しく取得できます。

ヘッダーの高さを取得する

次に、

const headerHeight = $('header').outerHeight();

でヘッダーの高さを取得しています。

outerHeight()は、要素の高さに加えて、paddingやborderなども含めた外側の高さを取得するjQueryのメソッドです。

例えばヘッダーの高さが80pxだった場合、

headerHeight = 80

という値になります。

この値を後ほどスクロール位置の調整に利用します。

ページ内リンクを取得する

次に、

$('a[href^="#"]').click(function () {

としています。

ここでは、href属性が#から始まるaタグを取得しています。

例えば、

<a href="#about">About</a>
<a href="#service">Service</a>
<a href="#contact">Contact</a>

などが対象になります。

href^="#"^=は、「指定した文字列で始まる」という意味です。

そのため、

#about
#service
#contact

のようなページ内リンクをまとめて対象にできます。

クリックされたリンク先を取得する

続いて、

const speed = 600;
let href = $(this).attr("href");
let target = $(href == "#" || href == "" ? "html" : href);

としています。

const speed = 600;

const speed = 600;

は、スクロールアニメーションの速度を指定しています。

単位はミリ秒なので、600の場合は0.6秒です。

例えば、

const speed = 1000;

とすれば1秒かけてスクロールします。

$(this).attr("href")

let href = $(this).attr("href");

では、クリックされたリンクのhref属性を取得しています。

例えば、

<a href="#contact">お問い合わせ</a>

をクリックした場合、

href = "#contact"

となります。

スクロール先を取得する

let target = $(href == "#" || href == "" ? "html" : href);

では、取得したhrefをもとにスクロール先を指定しています。

href#または空の場合はhtmlを対象とし、それ以外の場合は指定されたIDを持つ要素を対象にします。

ヘッダーの高さ分だけスクロール位置を補正する

今回のコードで最も重要なのが、この部分です。

let position = target.offset().top - headerHeight;

target.offset().topで、スクロール先となる要素のページ上部からの位置を取得します。

例えば、スクロール先がページ上部から1000pxの位置にあり、固定ヘッダーの高さが80pxだった場合、

1000px - 80px = 920px

となります。

つまり、1000pxまでスクロールするのではなく、920pxまでスクロールすることで、ヘッダーの下に隠れずにコンテンツを表示できるという仕組みです。

イメージすると、

通常のスクロール
1000px → コンテンツがヘッダーと重なる

ヘッダーの高さを考慮
1000px - 80px = 920px
↓
コンテンツがヘッダーの下に隠れない

という違いになります。

固定ヘッダーの高さを考慮したスムーススクロールでは、この「スクロール先の位置からヘッダーの高さを引く」という考え方がポイントです。

スムーススクロールを実行する

最後に、

$("body,html").animate({ scrollTop: position }, speed, "swing");
return false;

でスクロールを実行します。

animate()

$("body,html").animate({
  scrollTop: position
}, speed, "swing");

によって、指定した位置まで滑らかにスクロールします。

ここでは、

  • position:スクロール先
  • speed:スクロール速度
  • swing:アニメーションの動き方

を指定しています。

return false

return false;

は、リンクをクリックしたときにブラウザが通常行うページ内リンクへのジャンプをキャンセルするために使用しています。

これによって、通常の瞬間的なページ内移動ではなく、jQueryのアニメーションによるスムーススクロールが実行されます。

スクロール速度を変更する

スクロール速度は、

const speed = 600;

の数値を変更することで調整できます。

例えば、

const speed = 300;

とすれば、より素早くスクロールします。

反対に、

const speed = 1000;

とすれば、ゆっくりスクロールします。

サイトのデザインやページの長さに合わせて、ユーザーが違和感を感じない速度に調整するとよいでしょう。

ヘッダーの高さがPCとスマートフォンで違う場合

実際のWebサイトでは、PCとスマートフォンでヘッダーの高さが異なることがあります。

例えば、

PC:80px
スマートフォン:60px

のようなケースです。

今回のコードではページ読み込み時に、

const headerHeight = $('header').outerHeight();

としてヘッダーの高さを取得しているため、ページ読み込み時点のヘッダーサイズを基準にしています。

レスポンシブデザインによって画面幅に応じてヘッダーの高さが変化するサイトでは、より柔軟に対応するため、クリック時にヘッダーの高さを取得する方法もあります。

例えば、

let position = target.offset().top - $('header').outerHeight();

とすれば、リンクをクリックしたタイミングでヘッダーの高さを取得できます。

ヘッダーの高さが画面幅によって変わるサイトでは、このような方法も検討できます。

WordPressで使用する場合の注意点

WordPressサイトで今回のコードを使用する場合、テーマやプラグインによってページ内リンクの動作が独自に設定されている場合があります。

特に、

  • WordPressテーマ側ですでにスムーススクロールが設定されている
  • JavaScriptでページ内リンクを制御している
  • jQueryを別の処理でも使用している
  • ヘッダーの高さがレスポンシブで変化する
  • ハンバーガーメニューなどでヘッダーの構造が変わる

といった場合は、コードを追加するだけでは正常に動作しないことがあります。

既存サイトへ実装する場合は、現在のJavaScriptやテーマの仕様を確認したうえで追加することが重要です。

また、ページ内リンクのすべてを対象にする必要がない場合は、

$('a[href^="#"]')

のようにサイト全体のアンカーリンクをまとめて対象にするのではなく、特定のクラスを付けたリンクだけを対象にする方法もあります。

例えば、

<a href="#contact" class="smooth-scroll">お問い合わせ</a>

として、

$('.smooth-scroll').click(function () {

とすれば、.smooth-scrollが付いたリンクだけを対象にできます。

既存サイトへの実装では、こちらのほうが他のリンクへの影響を抑えやすい場合があります。

まとめ

今回は、固定ヘッダーの高さを考慮してページ内をスムーススクロールさせるjQueryコードを紹介しました。

通常のページ内リンクでは、スクロール先のコンテンツが固定ヘッダーの下に隠れてしまうことがあります。

その場合は、

let position = target.offset().top - headerHeight;

のように、スクロール先の位置からヘッダーの高さを引いて位置を補正することで対応できます。

今回のポイントをまとめると、

  • outerHeight()でヘッダーの高さを取得する
  • ページ内リンクをクリックしたときに処理を実行する
  • offset().topでスクロール先の位置を取得する
  • ヘッダーの高さを引いてスクロール位置を補正する
  • animate()で滑らかにスクロールさせる
  • PCとスマートフォンでヘッダーの高さが異なる場合は注意する
  • 既存サイトではテーマや他のJavaScriptとの競合を確認する

という仕組みです。

固定ヘッダーを使用しているWordPressサイトで、「ページ内リンクをクリックすると見出しがヘッダーに隠れてしまう」「スムーススクロールの位置を調整したい」といった場合に活用できます。

また、WordPressサイトではテーマやプラグインによって既にJavaScriptが設定されている場合もあるため、既存のコードとの競合には注意が必要です。

ホームページのJavaScript・jQueryの修正や、ページ内リンクの不具合、表示・動作トラブルなどでお困りの場合も対応しています。

365日対応・8:00〜23:00対応・最短即日対応で、原因が分からないホームページの不具合から、ちょっとしたコード修正まで対応しています。

目次