固定ヘッダーにページ内リンクの見出しが隠れるのを scroll-padding-top で一括で防ぐ
html { scroll-padding-top: ヘッダーの高さ; } を1行書いておくと、#見出し へのページ内リンクで飛んだときにブラウザがヘッダーの分だけ手前で止めてくれるので、見出しが固定ヘッダーの裏に潜らない。
どんな時に使う?
position: fixed/stickyのヘッダーがあるサイトで、目次やページ内リンクをクリックすると見出しがヘッダーに被る時- JS でスクロール位置を「ヘッダーの高さ分ずらす」処理を書いていて、それを CSS に置き換えたい時
コード
css
:root {
--header-height: 64px;
}
.site-header {
position: sticky;
top: 0;
height: var(--header-height);
}
/* スクロールコンテナ(ページ全体なら html)に付ける */
html {
scroll-padding-top: calc(var(--header-height) + 16px); /* 少し余白も足す */
scroll-behavior: smooth; /* 任意。なめらかにスクロール */
}scroll-padding-topは「スクロールで要素を表示するとき、スクロールコンテナの上端からこれだけ内側を表示の基準にする」指定。ページ内リンク(#id)、element.scrollIntoView()、Tab キーでのフォーカス移動などのスクロールにまとめて効く。- ページ全体がスクロールする場合は
htmlに付ける。bodyではないので注意。 - 特定の見出しだけ止まる位置を変えたい場合は、見出し側に
scroll-margin-topを付ける(こちらは止まる要素側に付ける指定)。
css
h2[id] {
scroll-margin-top: 1rem; /* scroll-padding-top に上乗せされる */
}注意点・対応状況
- 主要ブラウザすべてで使える。
- ヘッダーの高さが画面幅で変わる場合は、メディアクエリでカスタムプロパティを切り替えるか、高さを JS で測ってカスタムプロパティに入れる。
scroll-behavior: smoothは動きが苦手な人向けに@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }で切っておくとよい。- 目次側で「いま読んでいる項目」をハイライトしたい場合は :target-current で目次の「いま読んでいる項目」をCSSだけでハイライト と組み合わせられる。
- 元の投稿は制作会社の「先回り実装」紹介で、CSS の手段として
scroll-padding-topでの一括制御を挙げている。上のコードとscroll-margin-topの使い分けは補足として組み立てたもの。