固定ヘッダー(追従ヘッダー)があるサイトでアンカーリンクをクリックすると、移動先の見出しがヘッダーの下に隠れてしまうことがあります。本記事ではjQueryでヘッダーの高さを動的に取得してオフセット補正する方法を、基本からレスポンシブ対応・CSSのみの代替手段まで丁寧に解説します。
- 追従ヘッダーが原因でリンク先が隠れる問題の原因と解決策
- jQueryでヘッダー高さを動的取得してオフセット補正する方法
- レスポンシブ対応(画面幅でヘッダー高さが変わる場合)
- CSSのscroll-padding-topによる代替手段
- URLハッシュ直アクセス時の対応(ページロード時のずれ修正)
1. 問題の原因
固定ヘッダーを position: fixed で実装すると、ヘッダーはドキュメントフローから外れます。アンカーリンクのデフォルト動作は「要素の上端をビューポートの上端に合わせる」ため、固定ヘッダーがある場合はその分だけ見出しが隠れてしまいます。
固定ヘッダーの高さをCSSで設定しても、アンカーリンクのジャンプ先は調整されません。JavaScriptかCSSの
scroll-padding-top で補正が必要です。2. jQueryでオフセット補正する(基本実装)
ヘッダーの高さを outerHeight() で取得し、スクロール位置から引き算します。
$(function () {
// アンカーリンクのクリックイベント
$('a[href^="#"]').on('click', function (e) {
e.preventDefault();
var target = $(this.hash);
if (!target.length) return;
// ヘッダーの高さを動的に取得(paddingを含む外側の高さ)
var headerH = $('header').outerHeight() || 0;
var margin = 16; // ヘッダーと見出しの余白
var pos = target.offset().top - headerH - margin;
$('html, body').animate({ scrollTop: pos }, 500);
});
});
height(): コンテンツ高さのみinnerHeight(): コンテンツ + paddingouterHeight(): コンテンツ + padding + border(通常はこれを使う)outerHeight(true): コンテンツ + padding + border + margin
3. レスポンシブ対応(画面幅でヘッダー高さが変わる場合)
スマホとPCでヘッダー高さが異なる場合、クリック時に動的取得すれば自動的に対応できます。静的な変数に保存すると画面回転・リサイズで古い値が使われるため注意が必要です。
$(function () {
$('a[href^="#"]').on('click', function (e) {
e.preventDefault();
var target = $(this.hash);
if (!target.length) return;
// クリック時に毎回取得(レスポンシブ対応)
var headerH = $('#site-header').outerHeight() || 0;
var pos = target.offset().top - headerH - 16;
$('html, body').animate({ scrollTop: pos }, 500);
});
});
4. URLハッシュ直アクセス時のずれを修正
ページロード時に URL に #section1 などのハッシュが含まれている場合、ブラウザはデフォルト動作でスクロールしますが固定ヘッダー分のオフセットは補正されません。ロード完了後にスクロール位置を再調整します。
$(function () {
// ページロード時のハッシュ補正
if (location.hash) {
var target = $(location.hash);
if (target.length) {
// 一瞬待ってからスクロール(ブラウザの初期スクロールを上書き)
setTimeout(function () {
var headerH = $('header').outerHeight() || 0;
var pos = target.offset().top - headerH - 16;
$('html, body').scrollTop(pos); // アニメーションなし
}, 100);
}
}
// 通常のアンカーリンク
$('a[href^="#"]').on('click', function (e) {
e.preventDefault();
var target = $(this.hash);
if (!target.length) return;
var headerH = $('header').outerHeight() || 0;
$('html, body').animate({ scrollTop: target.offset().top - headerH - 16 }, 500);
});
});
5. CSSのscroll-padding-topによる代替手段
jQuery不要で解決できるモダンな方法です。scroll-padding-top を html タグに指定すると、スクロール時のオフセットをCSSだけで設定できます。
html {
scroll-behavior: smooth; /* スムーズスクロール */
scroll-padding-top: 80px; /* ヘッダー高さ分 */
}
ヘッダー高さをCSS変数で管理するとより柔軟です:
:root {
--header-h: 70px; /* ヘッダー高さ */
}
html {
scroll-padding-top: var(--header-h);
}
header {
height: var(--header-h);
}
IE非対応です。また、ヘッダー高さが動的に変わる場合(追従後縮小など)はCSSの固定値では対応しきれないため、その場合はJavaScriptと組み合わせてください。
6. ターゲット要素に疑似要素でオフセットを設定する方法
見出しなどのターゲット要素に ::before 疑似要素で透明な高さを設定し、その分上に余白を作る古典的な手法です。JavaScriptが不要な反面、全セクションにCSSを書く必要があります。
/* ターゲットになる全セクションに適用 */
.section {
scroll-margin-top: 80px; /* ヘッダー高さ分 */
}
/* 古い書き方(::before で疑似要素) */
.section::before {
content: "";
display: block;
height: 80px; /* ヘッダー高さ */
margin-top: -80px; /* 負のマージンで隠す */
visibility: hidden;
pointer-events: none;
}
7. 方法の比較
| 方法 | jQuery不要 | IE対応 | 動的ヘッダー高さ対応 | 実装コスト |
|---|---|---|---|---|
| jQuery offset補正 | 不要 | 可 | 可 | 低 |
| CSS scroll-padding-top | 不要 | 非対応 | 限定的(CSS変数) | 最低 |
| CSS scroll-margin-top | 不要 | 非対応 | 限定的 | 低(全要素にCSS) |
| ::before疑似要素 | 不要 | 可 | 不可 | 中(全要素にCSS) |
まとめ
固定ヘッダーによるアンカーリンクのずれは、jQueryなら outerHeight() で動的にヘッダー高さを取得して補正するのが確実です。モダン環境(IE非対応可)なら scroll-padding-top または scroll-margin-top のCSSのみで解決できます。動的にヘッダー高さが変わるサイトではJavaScriptによる動的取得が最も信頼性が高いです。
関連記事: jQueryでアンカーリンクのスムーズスクロールを実装する方法 / スクロールで追従するヘッダーの実装完全ガイド
よくある質問(FAQ)
target.offset().top - $("header").outerHeight() - 余白px で計算してください。CSSのみで解決するなら html { scroll-padding-top: ヘッダー高さ; } も有効です。height() はコンテンツ高さのみ、outerHeight() はpadding+borderを含む高さを返します。ヘッダーの実際の表示高さを取得するには通常 outerHeight() を使います。setTimeout() で少し待ってから$(location.hash).offset().top - headerH にスクロール位置を合わせます。$('header').outerHeight() で動的取得すれば自動的に対応できます。初期化時に変数に保存すると画面回転・リサイズで古い値が使われるため、毎回取得する方が確実です。scroll-padding-top(IE非対応)か scroll-margin-top を使います。JavaScriptを使う場合は element.getBoundingClientRect().top + window.scrollY - headerHeight で計算して window.scrollTo({ top: pos, behavior: "smooth" }) でスクロールします。

