【CSSのみ】たった数行で解決!固定ヘッダーとページ内リンクの被りを防ぐ scroll-padding-top の使い方

Webサイト制作をしていると、一度は必ずぶつかる壁がありますよね。 そう、「ページ内リンクで移動した先(見出し)が、固定ヘッダーの下に隠れてしまう問題」です。

以前の記事では、GSAP(ScrollToPlugin)を使ってこの問題を解決しつつ、リッチなスムーススクロールを実装する方法をご紹介しました。

アニメーションを細かく制御したい場合はGSAPがとても便利ですが、「シンプルなサイトだから、JavaScriptのライブラリは読み込みたくない」「サクッと簡単に直したい」というケースも多いですよね。

実は今、モダンなブラウザであればCSSをたった数行追記するだけで、この問題をスッキリ解決できちゃうんです!

今回は、CSSプロパティ scroll-padding-top を使って、固定ヘッダーとページ内リンクの被りを防ぐ、超お手軽な実装方法をご紹介します!

実際の動作デモ

まずはデモ動作を確認してみてください!
ヘッダーのアンカーリンクをクリックすると対象のセクションへスクロールします!

See the Pen scroll-padding-top by yoshi (@mikanbako) on CodePen.

各セクションへスムーススクロールしつつ、ヘッダーと被さらない位置に移動することが確認できます!

実装コードの紹介

まずは、実際に動かすためのコードをご紹介します。
驚くほどシンプルなので、HTMLとCSSの該当部分だけをサクッと見ていきましょう!

<header class="l-header">
  <h1>CodePen Demo</h1>
  <nav class="l-header__nav">
    <a href="#section1">セクション 1</a>
    <a href="#section2">セクション 2</a>
    <a href="#section3">セクション 3</a>
  </nav>
</header>

<main>
  <section id="section1" class="p-section sec1">
    <h2>セクション 1</h2>
    <p>ここはセクション1のコンテンツです。固定ヘッダーに隠れずにピタッと止まります!</p>
  </section>

  <section id="section2" class="p-section sec2">
    <h2>セクション 2</h2>
    <p>ここはセクション2のコンテンツです。scroll-behavior: smooth; のおかげで動きも滑らかです。</p>
  </section>

  <section id="section3" class="p-section sec3">
    <h2>セクション 3</h2>
    <p>ここはセクション3のコンテンツです。CSSだけで実装できるなんて便利ですよね!</p>
  </section>
</main>
html {
  /* ヘッダーの高さ分、スクロールの停止位置をずらす */
  scroll-padding-top: 80px; 
  /* ついでにスムーススクロールもCSSで実装 */
  scroll-behavior: smooth; 
}

たったこれだけです!たったこれだけの記述で、先ほどのデモのように見出しがピタッとヘッダーの下で止まってくれます。

コードの解説・こだわったポイント

「たった2行CSSを追記するだけ」のシンプルなコードですが、実務での運用やUX(ユーザー体験)を考慮して、このCSSアプローチを採用したのには理由があります。

以下の3つのポイントにこだわって実装しました。

JavaScript(ライブラリ)に依存しないパフォーマンスの高さ

スムーススクロールや停止位置の調整は、jQueryやJavaScriptでの実装が主流でした。しかし、今回のようなシンプルな要件であれば、CSSだけで完結させることでページの読み込み速度(パフォーマンス)の向上に繋がります。 また、他のJSコードとの競合やバグを気にしなくて良くなるため、保守性が高いのも大きなメリットです。

CSS変数(カスタムプロパティ)を活用した応用

ヘッダーの高さがレスポンシブで変わる場合

スマホとPCでヘッダーの高さが変わる場合、メディアクエリで都度 scroll-padding-top を上書きしても良いのですが、CSS変数を使うとさらにスマートです!

:root {
  /* ヘッダーの高さを変数として定義 */
  --header-height: 60px; 
}

@media (width >= 1024px) {
  :root {
    --header-height: 80px; /* PC時は80pxに変更 */
  }
}

html {
  /* 変数を読み込ませるだけ! */
  scroll-padding-top: var(--header-height); 
}

このように設計しておけば、後から「デザイン変更でヘッダーの高さを変えたい」となった時も、変数の値を1箇所変更するだけでサイト全体のスクロール位置調整も完了します。

UXを底上げする scroll-behavior: smooth

ヘッダーの被りを防ぐだけであれば scroll-padding-top だけで十分ですが、あわせて scroll-behavior: smooth を設定しています。

html {
  /* CSSだけでスムーススクロールにする! */
  scroll-behavior: smooth; 
}

パッと画面が切り替わるよりも、「スルーッ」と移動するアニメーションを挟むことで、ユーザーが「ページ内の別の場所に移動した」という空間の繋がりを直感的に把握しやすくなり、UXの向上に繋がります。

補足:ブラウザの対応状況について

今回使用したプロパティは、現在主流のモダンブラウザ(Chrome, Safari, Firefox, Edge)のほとんどでサポートされているため、安心して使用することが出来ます。

詳しいサポート状況や仕様については、以下のページも参考にしてみてください!

・Can I Use: scroll-padding
・Can I Use: scroll-behavior
・MDN: scroll-padding-top

まとめ

今回は、CSSの scroll-padding-top を使って、固定ヘッダーとページ内リンクの被りをサクッと防ぐ方法をご紹介しました。

以前の記事でご紹介したGSAPを使った実装と比べると、「なんだ、今はCSSだけでこんなに簡単に解決できるんだ!」と驚かれた方もいるかもしれません。

私自身、日々の作品作りを通して強く感じるのは、「何でもかんでも高度な技術(ライブラリ)を使えば良いというわけではない」ということです。

もちろん、複雑なアニメーションや細かい制御が求められる場面では、GSAPのようなツールが非常に強力な武器になります。しかし、今回のようなシンプルな要件であれば、CSSの標準機能を最大限に活かすことで、サイトのパフォーマンスも上がり、後々のメンテナンス(保守性)も楽になります。

大切なのは、そのプロジェクトの目的や規模に合わせて「最適な技術(適材適所)」を選択できる引き出しを持っておくことだと考えています。

これからも、ユーザーさんにとって心地よいUXを追求しつつ、裏側のコードはシンプルで保守しやすい、そんなバランス感覚を持ったフロントエンドエンジニアを目指して、日々学習とアウトプットを頑張っていきます!

最後まで読んでいただき、ありがとうございました!

Prev
Next