はじめに
固定ヘッダー(position: fixed)を使ったサイトでアンカーリンクをそのまま使うと、リンク先のコンテンツがヘッダーの裏に隠れてしまう問題が発生します。本記事では jQueryと matchMedia を組み合わせて、PCとスマートフォンで異なるヘッダー高さに対応したスムーズスクロールを実装する方法を解説します。
基本の実装コード
javascript
$(function () { // ブレイクポイントでヘッダー高さを切り替え var headerHeight = window.matchMedia('(min-width: 769px)').matches ? 160 : 80; $('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 }, 550, 'swing'); return false; });});JavaScriptコードの解説
① matchMedia でレスポンシブ対応
javascript
var headerHeight = window.matchMedia('(min-width: 769px)').matches ? 160 : 80;JavaScriptwindow.matchMedia() はCSSのメディアクエリをJavaScriptで判定できるAPIです。画面幅が 769px以上ならPC用の高さ(160px)、それ未満ならスマホ用の高さ(80px) をオフセット値として使います。
ポイント: ヘッダー高さはCSSの実際の値に合わせて調整してください。
② アンカーリンクのクリックイベント
javascript
$('a[href^=#]').click(function () { ... });JavaScripthref 属性が # から始まるリンクすべてに対してクリックイベントを設定します。
③ スクロール先の位置を計算
javascript
var position = target.offset().top - headerHeight;JavaScriptoffset().top で対象要素のページ上部からの距離を取得し、ヘッダー高さ分を引くことで、コンテンツが隠れない正確な位置に移動できます。
④ スムーズスクロール
javascript
$('html, body').animate({ scrollTop: position }, 550, 'swing');JavaScript550:スクロール速度(ミリ秒)"swing":イージング("linear"に変えると等速スクロールになります)
応用:画面リサイズにも対応する
ページ読み込み時だけでなく、ウィンドウのリサイズ時にも高さを再取得したい場合は以下のように書き換えます。
javascript
$(function () { function getHeaderHeight() { return window.matchMedia('(min-width: 769px)').matches ? 160 : 80; } $('a[href^=#]').click(function () { var href = $(this).attr('href'); var target = $(href === '#' || href === '' ? 'html' : href); var position = target.offset().top - getHeaderHeight(); // 毎回取得 $('html, body').animate({ scrollTop: position }, 550, 'swing'); return false; });});JavaScript応用:URLハッシュ付きで直接アクセスした場合にも対応
別ページから page.html#section のようにアクセスした場合、読み込み直後にブラウザが自動スクロールしてヘッダーに隠れてしまうことがあります。以下のコードで対処できます。
javascript
$(window).on('load', function () { if (location.hash) { var headerHeight = window.matchMedia('(min-width: 769px)').matches ? 160 : 80; var target = $(location.hash); if (target.length) { var position = target.offset().top - headerHeight; $('html, body').scrollTop(position); } }});JavaScript補足:CSSだけで解決する方法(モダンブラウザ向け)
jQueryを使わない場合、CSSの scroll-margin-top プロパティが便利です。
css
/* アンカーターゲットになる要素に設定 */section, h2, h3 { scroll-margin-top: 160px; /* ヘッダーの高さ */}@media (max-width: 768px) { section, h2, h3 { scroll-margin-top: 80px; }}CSSあわせて html に scroll-behavior: smooth; を指定すればjQueryなしでスムーズスクロールも実現できます。ただし IE非対応 のため、レガシーブラウザのサポートが必要な場合はjQuery版を使用してください。
まとめ
| 方法 | 対応ブラウザ | 柔軟性 |
|---|---|---|
| jQuery + matchMedia | IE含む広範囲 | 高い(細かく制御可能) |
CSS scroll-margin-top | モダンブラウザのみ | シンプルで手軽 |
固定ヘッダーのアンカーリンク問題はサイト制作でよく遭遇する課題です。プロジェクトの要件に合わせて適切な方法を選んでください。