目次
ヘッダーを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を指定するだけで解決します。
section {
scroll-margin-top: 100px; /* 固定ヘッダーの高さ */
}
これだけです。アンカーリンクでスクロールした際の「上端の余白」を指定するプロパティで、ネガティブマージンのような相殺テクニックが不要になります。背景色が付いていても問題なく、後述する従来手法のデメリットをすべて回避できます。主要ブラウザで広くサポートされているので、特別な理由がなければこの方法を選べば十分です。
以下は、scroll-margin-topが使えない環境や、既存コードの保守で従来手法を知っておきたい場合の参考です。
ターゲット要素にpadding-topで余白を作り、同じ分のネガティブマージンで相殺します。
section {
padding-top: 100px; /* 固定ヘッダーの高さ */
margin-top: -100px; /* 同じ分のネガティブマージンで相殺 */
}
シンプルですが、ターゲット要素に背景色が付いていると、余白部分にも背景色が乗ってしまい破綻します。
::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;
}
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方式・疑似要素方式も知っておくと対応の幅が広がります。