固定ヘッダーでアンカーリンクが隠れる問題の解決法【scroll-margin-top】

公開日
最終更新日
アンカーリンクのターゲット位置が固定ヘッダーと被らないように調整する

固定ヘッダーでアンカーリンクが隠れる原因

ヘッダーをposition: fixedで上部固定しているサイトでは、アンカーリンクで飛んだ先の要素が、固定ヘッダーの高さ分だけ隠れてしまうことがあります。リンクは正しく機能しているのに、見出しがヘッダーの裏に潜り込んで見えない、という状態です。

この記事では、最新のCSS(scroll-margin-top)による最も簡単な方法を中心に、従来のCSSテクニック2種とjQueryでの対応も含めて紹介します。今から実装するならscroll-margin-topが一番おすすめです。

前提となるHTMLはこんな構成です。

<div class="anchor">
  <ul>
    <li><a href="#sec1">アンカーリンク1</a></li>
    <li><a href="#sec2">アンカーリンク2</a></li>
    <li><a href="#sec3">アンカーリンク3</a></li>
  </ul>
</div>

<section id="sec1">
  <h2 class="ttl">セクション1の見出し</h2>
  <div>セクション1</div>
</section>

<section id="sec2">
  <h2 class="ttl">セクション2の見出し</h2>
  <div>セクション2</div>
</section>

<section id="sec3">
  <h2 class="ttl">セクション3の見出し</h2>
  <div>セクション3</div>
</section>

【推奨】scroll-margin-topで一発解決

現在のブラウザなら、ターゲット要素にscroll-margin-topを指定するだけで解決します。

section {
  scroll-margin-top: 100px; /* 固定ヘッダーの高さ */
}

これだけです。アンカーリンクでスクロールした際の「上端の余白」を指定するプロパティで、ネガティブマージンのような相殺テクニックが不要になります。背景色が付いていても問題なく、後述する従来手法のデメリットをすべて回避できます。主要ブラウザで広くサポートされているので、特別な理由がなければこの方法を選べば十分です。

以下は、scroll-margin-topが使えない環境や、既存コードの保守で従来手法を知っておきたい場合の参考です。

従来手法1:padding-topとネガティブマージン

ターゲット要素にpadding-topで余白を作り、同じ分のネガティブマージンで相殺します。

section {
  padding-top: 100px;  /* 固定ヘッダーの高さ */
  margin-top: -100px;  /* 同じ分のネガティブマージンで相殺 */
}

シンプルですが、ターゲット要素に背景色が付いていると、余白部分にも背景色が乗ってしまい破綻します。

従来手法2:before疑似要素で調整

::before疑似要素で空のブロックを差し込んで調整します。

section::before {
  content: "";
  display: block;
  height: 100px;       /* 固定ヘッダーの高さ */
  margin-top: -100px;  /* 同じ分のネガティブマージンで相殺 */
  visibility: hidden;
}

手法1より記述は増えますが、ターゲットごとに調整量を変えられます。背景色が付いている場合は、要素の最初の子要素に疑似要素を当てて回避します。

section .ttl::before {
  content: "";
  display: block;
  height: 100px;
  margin-top: -100px;
  visibility: hidden;
}

従来手法3:jQueryで対応

JavaScriptで制御する方法です。サイト全体のアンカーリンクに一括で効かせられます。

$(function () {
  var headerHeight = 100; // ヘッダーの高さ
  $('a[href^="#"]').click(function () {
    var href = $(this).attr("href");
    var target = $(href === "#" || href === "" ? "html" : href);
    var position = target.offset().top - headerHeight;
    $("html, body").animate({ scrollTop: position }, 500, "swing");
    return false;
  });
});

一括設定できる反面、ターゲットごとに調整量を変えられない点、スマホで位置がずれやすい点がデメリットです。なお、スムーズスクロール自体も今はCSSのscroll-behavior: smoothで実現できるため、この用途でjQueryを使う必要性は薄れています。

まとめ

固定ヘッダーでアンカーリンクが隠れる問題は、今ならscroll-margin-top一択です。ネガティブマージンの相殺も、背景色による破綻も気にする必要がありません。既存サイトの保守で従来手法に遭遇することもあるので、padding方式・疑似要素方式も知っておくと対応の幅が広がります。

IPPEI FUKUTA(株式会社バッズブルー 代表)

IPPEI FUKUTA(株式会社バッズブルー 代表)

WordPress専門のWeb制作者として15年・150サイト以上を担当。現場でつまずいた問題と解決策を、同じ制作者・フリーランスの方に向けて発信しています。無料のWeb便利ツール集「バドツール」を開発・運営中。