9/7まで 最大30%OFF 初心者編|無料コーディング教材|HTML・CSS・jQueryを実践で学ぶ

HTML・CSSでヘッダーを固定する方法|fixed・stickyの違いと重なり対策

パソコンとスマートフォンでヘッダーを固定し本文だけがスクロールする日本語の図

ページを下へスクロールしても、ロゴやメニューを画面上部へ残したいことはありませんか? HTMLでヘッダーの構造を作り、CSSのposition: fixedを指定すると固定できます。

ただし、固定するだけでは本文がヘッダーの下へ隠れたり、スマートフォンで表示領域が狭くなったりします。この記事では、変更前の状態からコードを追加し、重なりを防ぎながら固定する手順を初心者向けに解説します。

先に結論をいうと、常に画面上部へ固定するならposition: fixed、元の位置までスクロールした後だけ固定するならposition: stickyが基本です。どちらもtopz-indexをあわせて設定します。

固定する前にヘッダーのHTMLを用意する

まず、header要素の中へロゴとナビゲーションを配置します。この記事では固定方法に集中するため、メニューはシンプルな3項目にしています。

ヘッダー自体の作り方やheadernav要素の役割から確認したい場合は、次の記事も参考にしてください。

変更前はヘッダーも本文と一緒にスクロールする

次のHTMLをindex.htmlへ保存します。ナビゲーションのリンク先は練習用なので、実際のサイトでは正しいURLへ置き換えてください。

<!doctype html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>固定ヘッダーの練習</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header class="site-header">
    <div class="header-inner">
      <a class="site-logo" href="/">SAMPLE SITE</a>

      <nav class="global-nav" aria-label="メインメニュー">
        <ul>
          <li><a href="/">ホーム</a></li>
          <li><a href="/works/">制作実績</a></li>
          <li><a href="/contact/">お問い合わせ</a></li>
        </ul>
      </nav>
    </div>
  </header>

  <main class="main-content">
    <section id="about">
      <h1>固定ヘッダーのサンプル</h1>
      <p>ここにページの本文が入ります。</p>
    </section>

    <section id="works">
      <h2>制作実績</h2>
      <p>スクロール確認用のコンテンツです。</p>
    </section>
  </main>
</body>
</html>

続いて、固定前の見た目を整えるCSSを書きます。この段階ではpositionを指定していないため、スクロールするとヘッダーも画面の上へ移動します。

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  color: #172033;
  font-family: system-ui, sans-serif;
  background: #f7f9fc;
}

.site-header {
  height: 80px;
  background: #0f2a56;
  color: #ffffff;
}

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: min(100% - 32px, 1120px);
  height: 100%;
  margin-inline: auto;
}

.site-logo {
  color: inherit;
  font-size: 1.25rem;
  font-weight: 700;
  text-decoration: none;
}

.global-nav ul {
  display: flex;
  gap: 24px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.global-nav a {
  color: inherit;
  text-decoration: none;
}

.global-nav a:hover,
.global-nav a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 4px;
}

.main-content {
  width: min(100% - 32px, 960px);
  margin-inline: auto;
}

.main-content section {
  min-height: 70vh;
  padding-block: 48px;
}

position: fixedでヘッダーを画面上部へ固定する

変更前のCSSへ、次の内容を追加します。--header-heightは、同じ高さを複数箇所で使うためのCSSカスタムプロパティ(変数)です。

:root {
  --header-height: 80px;
}

body {
  padding-top: var(--header-height);
}

.site-header {
  position: fixed;
  z-index: 1000;
  top: 0;
  right: 0;
  left: 0;
  height: var(--header-height);
}

position: fixedを指定した要素は通常の配置の流れから外れ、画面を基準に固定されます。top: 0で上端へ置き、right: 0left: 0で画面幅いっぱいに広げています。

z-index: 1000は重なり順を前面にする指定です。ただし、数字を無制限に大きくするのではなく、サイト内で重なり順のルールを決めて使うと管理しやすくなります。

本文がヘッダーの下へ隠れるのを防ぐ

fixedにしたヘッダーは通常の配置から外れるため、そのままでは本文の先頭へ重なります。そこで、bodyの上側へヘッダーと同じ80pxの余白を入れています。

本文が固定ヘッダーに隠れる修正前と80pxの余白を追加した修正後の比較図
ヘッダーの高さと同じ余白を本文の上へ追加すると重なりを防げます

画像左の変更前では、CONTENTの上部がヘッダーに隠れています。画像右の変更後では、ヘッダーの高さと同じ余白があるため、本文が正しい位置から表示されます。

ヘッダーの高さだけを変更して余白を更新し忘れると、再び重なりや空きすぎが発生します。CSS変数で高さを一元管理しておけば、変更箇所を減らせます。

ページ内リンクの見出しが隠れないようにする

href="#works"のようなページ内リンクを押すと、移動先の見出しが固定ヘッダーの裏へ入る場合があります。次のCSSを追加すると、移動位置へヘッダー分の余白を確保できます。

html {
  scroll-padding-top: calc(var(--header-height) + 16px);
}

scroll-padding-topは、スクロールで移動した位置の上側へ余白を確保するプロパティです。16pxを加えているため、見出しとヘッダーの間にも少し空間が残ります。

スマートフォンでは固定ヘッダーを小さくする

スマートフォンは表示領域が狭いため、80pxのヘッダーを固定すると本文を読む範囲が小さくなります。画面幅768px以下で高さを64pxへ変更し、メニュー間隔も狭くします。

@media (max-width: 48rem) {
  :root {
    --header-height: 64px;
  }

  .header-inner {
    width: min(100% - 24px, 1120px);
  }

  .site-logo {
    font-size: 1rem;
  }

  .global-nav ul {
    gap: 12px;
    font-size: 0.875rem;
  }

  .global-nav li:nth-child(2) {
    display: none;
  }
}

ここでは制作実績のリンクを省き、ホームとお問い合わせだけを表示しています。必要なリンクが多い場合は、無理に横へ詰め込まず、開閉できるメニューボタンへ切り替えましょう。

レスポンシブ対応の考え方やメディアクエリを詳しく確認したい場合は、次の記事で手順を解説しています。

position: stickyで途中から固定する方法

ページを開いた直後から画面へ固定する必要がない場合は、position: stickyも選べます。要素が元の位置にある間は通常どおり表示され、上端へ到達した後だけ固定されます。

.site-header {
  position: sticky;
  z-index: 1000;
  top: 0;
}

body {
  padding-top: 0;
}

stickyは通常の配置の流れに残るため、fixedのようにヘッダー分のpadding-topを追加する必要はありません。最初から上端にあるヘッダーでは見た目が似ますが、仕組みは異なります。

指定固定の基準本文の重なり対策向いている用途
fixed基本的に画面ヘッダー分の余白が必要常に表示したいサイトヘッダーや操作ボタン
stickyスクロールする親要素通常は不要途中から固定したい見出しやサイドバー

固定ヘッダーのメリット

別ページへ移動しやすい

長いページを読んでいる途中でも、メニューが見えていれば目的のページへすぐ移動できます。一番上まで戻る操作が不要になり、問い合わせや関連情報への導線を保てます。

現在いるサイトを把握しやすい

ロゴや主要メニューが残るため、スクロール後もサイトの全体像を把握しやすくなります。ページが長いほど、共通ナビゲーションが見える安心感を得やすいでしょう。

固定ヘッダーのデメリットと注意点

本文を読む領域が狭くなる

固定ヘッダーは常に画面の一部を使います。特にスマートフォンでは高さを抑え、主要なリンクだけを残すことが大切です。

必要のないページでは邪魔になる

短いページや集中して文章を読むページでは、固定しないほうが見やすい場合もあります。「よく使う操作を常に見せる必要があるか」を基準に判断しましょう。

ヘッダーを固定できないときの確認方法

本文がヘッダーの下へ隠れる

bodypadding-topが、固定ヘッダーの高さと一致しているか確認します。ブラウザの開発者ツールでヘッダーの実際の高さを確認すると原因を見つけやすくなります。

ヘッダーが本文の後ろへ隠れる

z-indexpositionが両方指定されているか確認します。それでも直らない場合は、親要素のtransformopacityなどが別の重なり順を作っていないか調べます。

z-indexが効く条件や重なり順の確認方法は、次の記事で詳しく解説しています。

position: stickyが固定されない

top: 0の指定を忘れていないか確認します。また、親要素のoverflowhiddenautoになっていると、その親要素がスクロールの基準になる場合があります。

ヘッダーの幅が画面からはみ出す

固定する要素へ固定幅を設定していないか確認します。right: 0left: 0を使い、中の.header-innerで最大幅を管理するとレスポンシブ対応しやすくなります。

固定ヘッダーに関するよくある質問

HTMLだけでヘッダーを固定できますか?

HTMLだけでは固定できません。HTMLでヘッダーの構造を作り、CSSでposition: fixedまたはposition: stickyを指定します。

JavaScriptは必要ですか?

最初から固定するだけなら必要ありません。一定量スクロールした後で固定したり、下へスクロールしたときに隠して上へ戻るときだけ表示したりする場合は、JavaScriptでスクロール状態を判定します。

スマホでも固定したほうがよいですか?

必ず固定する必要はありません。画面を占有しすぎる場合は、ヘッダーを低くする、表示するリンクを減らす、スマートフォンだけ固定を解除する、といった調整が有効です。

まとめ

HTMLのヘッダーを常に画面上部へ固定するには、CSSでposition: fixedtop: 0z-indexを指定します。本文が隠れないよう、ヘッダーと同じ高さの上余白も忘れずに追加してください。

途中から固定する場合はposition: stickyも選べます。パソコンとスマートフォンの両方でスクロールし、本文の重なり、ページ内リンク、メニューの押しやすさまで確認できれば完成です。