ヘッダーを上に固定するCSS|position: stickyの使い方と止まらない原因、コピペで使える4種類と使う・使わないの判断

ヘッダーを上に固定するCSS。position: stickyが止まらない原因と、使う・使わないの判断

ページを下へ読み進めても、ヘッダーやメニューが画面の上に残り続ける。よく見かけるこの形は、CSSの position: sticky(ポジション・スティッキー:スクロールすると、決めた位置にくっつく指定)でできます。JavaScriptは要りません。

使いどころ

縦に長いページで、読んでいる途中にメニューや「今どこか」が必要になる場所に使う。1画面で終わる短いページや、スマホで画面の上を大きくふさぐ場合は固定しない。

今回は、ヘッダーを上に固定する基本の形、見出しが入れ替わる一覧、表の見出し行の固定、横の目次の固定の4種類を、コピペ用のコードつきで紹介します。あわせて、「書いたのに止まらない」ときに見直す3つの場所もまとめました。

トミー

連載「WEBの技術」の17回目です。
今回は「ヘッダーを上に固定する」。position: sticky の使い方を見ていきます。

完成見本:スクロールしても、ヘッダーが上に残る

下の見本は、小さな画面の中を自動で下へスクロールさせています。灰色の線が本文の代わりです。本文は上へ流れていきますが、「KAKERU」と書いたヘッダーだけは、画面の上にくっついたまま動きません。

STICKY HEADER1. ヘッダーを上に固定サイト全体のヘッダー・メニュー

※ 見本は見た目を見せるためのもので、読み上げソフトでは読まれないようにしています。端末の「動きを減らす」設定がオンのときは、自動ではスクロールしません。触っている間も止まります。

コピペ用のコード

CSSは、サイトのCSSファイルや、WordPressならテーマの「追加CSS」などに入れます。クラス名の頭の kd-stk は、サイトのほかのデザインと名前がぶつからないようにするための目印です。見本の灰色の線(本文の代わり)のCSSは、コピペ用のコードには入れていません。

WordPressのテーマには、ヘッダーを固定する設定を最初から持っているものがあります。テーマの設定で固定できる場合は、そちらを使うほうが、テーマの更新で崩れる心配が少なくなります。

1. ヘッダーを上に固定

いちばん基本の形です。ページの先頭にあるヘッダーが、下にスクロールすると画面の上にくっついて、そのまま付いてきます。position: sticky と top: 0 の2行が中心で、本文の上に重なるように z-index と背景色を付けています。

HTML
<header class="kd-stk-header">
  <a class="kd-stk-logo" href="/">KAKERU</a>
  <nav class="kd-stk-nav" aria-label="メインメニュー">
    <a href="/works/">実績</a>
    <a href="/price/">料金</a>
    <a href="/contact/">相談</a>
  </nav>
</header>
<main>
  <!-- ここに本文 -->
</main>
CSS
.kd-stk-header {
  /* スクロールして画面の上に着いたら、そこで止める */
  position: sticky;
  top: 0;
  /* 本文より手前に出す */
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  /* 背景色がないと、下を流れる本文が透けて見える */
  background: #FFFFFF;
  border-bottom: 1px solid #D8E6F0;
}
.kd-stk-logo {
  font-weight: 800;
  color: #10283A;
  text-decoration: none;
}
.kd-stk-nav {
  display: flex;
  gap: 14px;
  font-size: 13px;
}
.kd-stk-nav a {
  color: #0284C7;
  text-decoration: none;
}

2. 見出しが入れ替わる一覧

見出しを固定した形です。見出しは、自分のまとまり(section)の中でしか動けません。そのため、次のまとまりの見出しが下から来ると、前の見出しを押し上げて入れ替わります。長い一覧で「今どこを読んでいるか」が分かります。

HTML
<section class="kd-stk-sec">
  <h2 class="kd-stk-sec-title">あ行</h2>
  <ul>
    <li>アクセシビリティ</li>
    <li>アイキャッチ</li>
  </ul>
</section>
<section class="kd-stk-sec">
  <h2 class="kd-stk-sec-title">か行</h2>
  <ul>
    <li>カテゴリー</li>
    <li>キャッシュ</li>
  </ul>
</section>
<!-- 同じ形のまとまりをくり返す -->
CSS
.kd-stk-sec-title {
  position: sticky;
  top: 0;
  z-index: 1;
  margin: 0;
  padding: 6px 14px;
  font-size: 14px;
  font-weight: 800;
  color: #FFFFFF;
  background: #0284C7;
}
.kd-stk-sec ul {
  margin: 0;
  padding: 8px 14px 14px 32px;
  font-size: 13px;
  line-height: 1.9;
}

3. 表の見出し行を固定

表のいちばん上の行(thead の th)を固定した形です。縦に長い表でも、下まで読んだときに「この列は何だったか」を見失いません。表の線は、見出しのすぐ下の線もいっしょに付いてくるように、border-collapse: separate で1マスずつ引いています。

HTML
<table class="kd-stk-table">
  <thead>
    <tr><th>プラン</th><th>内容</th><th>期間</th></tr>
  </thead>
  <tbody>
    <tr><td>ライト</td><td>5ページ</td><td>2週間</td></tr>
    <tr><td>スタンダード</td><td>10ページ</td><td>1か月</td></tr>
    <!-- 同じ形の行をくり返す -->
  </tbody>
</table>
CSS
.kd-stk-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: 13px;
}
.kd-stk-table th,
.kd-stk-table td {
  padding: 8px 10px;
  border-bottom: 1px solid #D8E6F0;
  text-align: left;
}
.kd-stk-table thead th {
  /* 見出しの行を、表の上に止める */
  position: sticky;
  top: 0;
  z-index: 1;
  color: #10283A;
  background: #E0F2FE;
}

4. 横の目次を固定

2列のレイアウトで、横の目次だけを固定した形です。本文を読み進めても、目次が画面の上のほうに残ります。グリッドの中の部品は、何もしないと本文と同じ高さまで伸びて動く余地がなくなるので、align-self: start で自分の高さに戻しています。スマホの幅では1列にして、固定をやめます。

HTML
<div class="kd-stk-layout">
  <nav class="kd-stk-side" aria-label="目次">
    <ol>
      <li><a href="#s1">はじめに</a></li>
      <li><a href="#s2">準備するもの</a></li>
      <li><a href="#s3">手順</a></li>
    </ol>
  </nav>
  <div>
    <h2 id="s1">はじめに</h2>
    <!-- ここに本文 -->
  </div>
</div>
CSS
.kd-stk-layout {
  display: grid;
  grid-template-columns: 180px 1fr;
  gap: 24px;
}
.kd-stk-side {
  position: sticky;
  /* 画面の上から16px下で止める */
  top: 16px;
  /* 本文と同じ高さまで伸びないようにする */
  align-self: start;
  padding: 12px 14px;
  font-size: 13px;
  line-height: 1.9;
  background: #F2F8FC;
  border-radius: 10px;
}
.kd-stk-side ol {
  margin: 0;
  padding-left: 1.4em;
}
/* スマホの幅では1列にして、固定しない */
@media (max-width: 599px) {
  .kd-stk-layout { grid-template-columns: 1fr; }
  .kd-stk-side { position: static; }
}

仕組み:「普段は普通に並び、ある位置からくっつく」

固定するための指定は、くっつけたい部品に書く2行だけです。

/* くっつけたい部品に書く */
position: sticky;
top: 0;   /* 上から0pxの位置で止める */

1. 途中までは、普通の部品として並ぶ

position: sticky を付けた部品は、スクロールする前は、ほかの部品と同じように普通の位置に並びます。ページの先頭にあるヘッダーなら、先頭にそのまま表示されます。

2. top の位置に来たら、そこで止まる

下へスクロールして、部品の上の端が top で決めた位置(top: 0 なら画面のいちばん上)に来ると、そこから先は止まったままになります。MDNでは、top・bottom などのどれかを書かないと、position: relative(元の位置のまま)と同じ動きになると説明されています。

3. 動けるのは、親の箱の中だけ

くっついた部品も、自分を包んでいる親の箱の外へは出られません。親の箱の下の端が来ると、いっしょに押し上げられて画面から消えます。2の見本で見出しが入れ替わるのは、この性質を使っています。見出しはそれぞれのまとまり(section)の中でしか動けないので、まとまりが終わると次の見出しに場所をゆずります。

position: fixed との違い

似た指定に position: fixed(画面に固定する指定)があります。fixed は最初から画面に貼りつき、元の場所からは抜けるので、下の本文がヘッダーの裏にもぐり込みます。それを防ぐために本文の上に余白を足す手間がかかります。sticky は元の場所を残したまま止まるので、その余白が要りません。

position: sticky は、2019年9月から主要なブラウザでそろって使えるようになり、2022年3月からは「Baseline」の広く使える段階になっています(表の見出しへの sticky も含みます)。今のブラウザなら、特別な対策なしで使えます。

書いたのに止まらないときに見直す3つの場所

よくある原因何が起きているか直し方
top を書いていないtop などがないと、relative と同じ動きになるtop: 0 などを書く
親の箱に overflow: hidden などがあるその箱を基準にくっつこうとするので、ページのスクロールでは止まらない親の overflow を外す。横のはみ出しを隠したいだけなら overflow: clip を試す
親の箱が、部品と同じ高さしかない親の中に動ける余地がないので、くっつく前に親ごと流れていく固定したい部品を、高さのある親の中に置く。グリッドやフレックスの中なら align-self: start

2つ目は、MDNに「overflow が hidden・scroll・auto などの、いちばん近い親にくっつく。その親が実際にスクロールしていなくても」と書かれています。テーマのCSSで、ページ全体を包む箱に overflow: hidden が付いていることがあり、ヘッダーが止まらない原因になります。WordPressで止まらないときは、ブラウザの「検証」機能で、親の箱を順にたどって確かめます。

数値を変えるとどうなるか

top の値(1の見本)

同じヘッダーで、top だけを変えて並べました。

top: 0:画面の上にぴったり止まる
top: 10px:上にすき間を残して止まる
top を書かない:止まらずに流れていく

top: 0 は画面の上の端にぴったり止まります。top: 10px にすると、上に10pxのすき間を残して止まるので、角を丸めて浮いたカードのように見せる形に使えます。top を書かないと、position: sticky を書いていても止まらずに流れていきます。

変えるところ小さくすると大きくすると
top の値0 なら画面の上の端にぴったり止まる上にすき間が空き、そのぶん本文の見える量が減る
ヘッダーの高さ(padding)本文の見える量が増えるスマホでは画面の上を大きくふさぐ
z-index本文の画像や見本が、ヘッダーの上に重なることがある本文より手前に出る。サイトのほかの部品より大きい数にする

スマホと、見る人への配慮

スマホでは、高さを小さく

スマホの画面は縦が限られています。高さ80pxのヘッダーを固定すると、横向きにしたときなどに、本文を読める場所がかなり狭くなります。固定するなら、ロゴとメニューのボタンだけにして高さを抑えます。それでも大きいなら、スマホでは固定しない、という判断もあります。

ページ内リンクと、キーボードで選んだ部品が隠れないように

ヘッダーを固定すると、目次から「#手順」のようなページ内リンクで飛んだとき、飛んだ先の見出しがヘッダーの裏に隠れることがあります。キーボードの Tab キーで部品を選んだときも同じで、選んだボタンがヘッダーの下にもぐって見えなくなることがあります。

W3Cのアクセシビリティの基準(WCAG 2.2)には、キーボードで選んだ部品が、固定したヘッダーなどで完全に隠れないようにする項目があり、その方法として scroll-padding が挙げられています。ページ全体に、ヘッダーの高さぶんの余白を指定します。

/* ヘッダーの高さが56pxなら、少し足して64px */
html {
  scroll-padding-top: 64px;
}

背景色とコントラスト

ヘッダーに背景色を付けないと、下を流れる本文が透けて重なり、文字が読めなくなります。半透明の背景にする場合も、下に写真が来たときにメニューの文字が読めるかを確かめます。

やりすぎ注意

固定する部品を増やすほど、本文を読める場所は狭くなります。ヘッダーの下にお知らせの帯、さらに下に目次と、何段も固定すると、スマホでは本文が画面の半分ほどになることもあります。1ページで固定するのは、基本は1つまでにします。

トミー

固定するものは「読んでいる途中で、何度も使うもの」だけに絞っています。
一度見れば済むお知らせまで付いてくると、読む邪魔になります。

AIに頼むなら

ヘッダーの固定は、Claudeなどの生成AIに頼んでもすぐ作ってもらえます。そのときは「sticky で」「止める位置」「スマホでの扱い」「ページ内リンク」まで、まとめて伝えると手直しが少なく済みます。

サイトのヘッダーを、スクロールしても画面の上に残るように、HTMLとCSSで作って。JavaScriptは使わない。
position: sticky と top: 0 を使い、背景は白、本文より手前に出す。スマホでは高さ56px以内にする。
ページ内リンクで飛んだ先が隠れないように、html に scroll-padding-top も付けて。

AIが出したコードは、そのまま使う前に、次の3つを確かめます。

  • 実際のサイトに入れて、止まるか。AIのコードは単体では動いても、テーマの親の箱に overflow: hidden があると止まりません。止まらないときは、上の「見直す3つの場所」を順に確かめます
  • fixed になっていないか。position: fixed で作ってくることがあります。その場合、ページの先頭で本文の上の部分がヘッダーの裏に隠れていないかを見ます
  • スマホの横向きで、本文が読めるか。スマホを横にしたときに、ヘッダーが画面の多くをふさいでいないかを確かめます。目次からのページ内リンクと、Tab キーで選んだときの見え方もあわせて試します

KAKERUならこう使う/使わない

最後に、作り手としての判断です。

使う場面

  • 縦に長いページのヘッダー。サービス紹介や記事のように、下まで読んでから「相談する」「ほかのページを見る」に進んでほしいページでは、メニューを上に残します。ボタンを探して上まで戻る手間がなくなります
  • 料金表・比較表の見出し行。行が10を超える表では、3の見本のように見出しを固定します。下のほうで「この列は何だったか」と上へ戻る必要がなくなります
  • マニュアルや長い記事の、パソコンでの目次。画面の横に余裕があるパソコンでは、4の見本のように目次を横に残します。スマホでは固定をやめて、記事の先頭に置きます

使わない場面

  • 1〜2画面で終わる短いページ。スクロールがほとんどないなら、固定しても違いが出ず、ヘッダーのぶん画面が狭くなるだけです
  • キャンペーンの帯やお知らせ。一度読めば済むものを固定すると、読み終わったあとも画面をふさぎ続けます。閉じるボタンを付けても、閉じる手間が増えます
  • スマホで高さのあるヘッダー。ロゴを大きく見せたい、検索欄も入れたい、とヘッダーが高くなるなら、スマホでは固定しない作りにします
トミー

「いつでも押せるようにしたいから固定」ではなく、「読んでいる途中で必要になるから固定」。
この順番で考えると、固定するものが増えすぎません。

まとめ

  • ヘッダーの固定は、くっつけたい部品に position: sticky と top: 0 の2行で作れる
  • sticky は、途中まで普通に並び、top の位置に来たら止まる。動けるのは親の箱の中だけ
  • top を書かない、親に overflow: hidden がある、親に動く余地がない。この3つが止まらない原因になりやすい
  • 背景色と z-index を付けて、本文が透けたり上に重なったりしないようにする
  • html に scroll-padding-top を付けて、ページ内リンクの飛び先や、キーボードで選んだ部品が隠れないようにする
  • 固定するのは、読んでいる途中で何度も使うものだけ。スマホでは高さを抑えるか、固定しない

まずは1の「ヘッダーを上に固定」のコードをコピーして、縦に長いページで下までスクロールしてみてください。止まらないときは、親の箱の overflow から確かめるのが近道です。

参考にした資料

いずれも2026年10月22日に確認しました。ブラウザの対応状況は変わることがあります。最新の情報は各ページでご確認ください。

ふだんの制作の話や、作ったものの裏側は Instagram と X でも出しています。

関連記事

横にスクロールするスライドをCSSだけで。scroll-snapの止め方と、使う・使わないの判断
カードを並べるCSS。グリッドで自動で折り返す、auto-fillとauto-fitの違いと使う・使わないの判断
押すと切り替わるタブをCSSだけで コピペで使える5種類と、使う・使わないの判断
ヘッダーを上に固定するCSS。position: stickyが止まらない原因と、使う・使わないの判断

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

CAPTCHA