
ページ内リンクで移動したら、見出しが固定ヘッダーの下に潜って読めない——この問題はCSSのscroll-margin-topを1行書くだけで解決します。JavaScriptでのオフセット計算は不要です。この記事では、当社サイトのTOPからサービス紹介ページの各セクションへアンカーリンクを張ったときに実際に使った実装をそのまま紹介します。
背景: アンカーリンクと固定ナビは相性が悪い
当社サイトのTOPには、5つのサービスを紹介するカードが並んでいて、クリックするとサービス紹介ページの該当セクションへ飛ぶようにしました。
<a class="card" href="/services/#ai-agent"> … </a>
<a class="card" href="/services/#ai-automation"> … </a>
<a class="card" href="/services/#web"> … </a>
リンク先のページでは、各セクションに対応するidを振っています。
<section class="sv-item" id="web"> … </section>
ただ、これだけだと問題が起きます。ブラウザはアンカー先の要素を画面の最上端に合わせてスクロールするため、上部に固定ナビ(position:fixedやsticky)があるサイトでは、着地した見出しがナビの裏に隠れてしまうのです。
解決: scroll-margin-top
着地先の要素に、ナビの高さぶんのscroll-margin-topを指定するだけです。
.sv-item{
scroll-margin-top: 84px; /* アンカー着地時に固定ナビへ潜らせない */
}
これは「スクロールで位置合わせをするときだけ効くマージン」で、通常のレイアウトには一切影響しません。ブラウザがアンカーへスクロールする際、要素の上に84pxの余白があるものとして着地位置を計算してくれます。当社の固定ナビは高さ50〜70px程度(画面幅で変わります)なので、少し余裕を持たせて84pxにしました。
ひと昔前は「擬似要素で不可視のパディングを作る」「JavaScriptでscrollToのY座標を補正する」といった回避策が定番でしたが、今は主要ブラウザすべてがscroll-margin-topに対応しています。1行で済むものに数十行かける理由はもうありません。
ハマりポイント: 効いていないように見えるとき
実装自体は1行ですが、確認時に「効いていない?」と感じやすい点が2つあります。
- 指定する場所を間違えている: scroll-margin-topを付けるのはリンク元ではなく着地先の要素(idを持つ要素)です。リンクの<a>側に書いても何も起きません。
- ページ最下部付近のセクションでは効果が見えない: ページの残りが短いと、そもそもブラウザがそれ以上スクロールできないため、指定位置まで下がりきらずに止まります。これは仕様どおりの挙動で、バグではありません。
まとめ
固定ナビのあるサイトでアンカーリンクを使うなら、着地先にscroll-margin-top。これだけ覚えておけば、ページ内リンクの「見出しが隠れる」問題はほぼ片付きます。似た仲間に、スクロールスナップやフォーカス移動にも効くscroll-padding(こちらはスクロールコンテナ側に指定)もあります。
Webサイトの構築や、こうした細部の使い勝手まで含めた設計のご相談は、SERVICESからお気軽にどうぞ。
← TECH-BLOG一覧へ