CSSで追従ヘッダー(固定ヘッダー)を作る方法を解説します。
基本の position: fixed から、position: sticky との使い分け、スクロール時の影やぼかし効果、上スクロールで表示・下スクロールで非表示にするパターン、コンテンツのずれ防止まで、実務で必要になる実装パターンを網羅します。
position: fixed で追従ヘッダーを作る(基本)
もっとも基本的な方法は、position: fixed でヘッダーをビューポートに固定することです。
<header class="header">
<nav>
<a href="/">サイト名</a>
<ul>
<li><a href="#about">About</a></li>
<li><a href="#service">Service</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<main class="main">
<p>コンテンツ</p>
</main>
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 60px;
background: #fff;
z-index: 1000;
}
position: fixed はビューポート(画面)を基準に位置を固定するため、スクロールしても常に画面上部に表示されます。
コンテンツのずれを防ぐ
position: fixed を使うと、ヘッダーが通常のフロー(文書の流れ)から外れるため、後続のコンテンツがヘッダーの裏に隠れてしまいます。
/* ヘッダーの高さ分だけ余白を追加 */
.main {
padding-top: 60px; /* ヘッダーの高さと同じ値 */
}
padding-top(または margin-top)にヘッダーの高さと同じ値を指定して、コンテンツがヘッダーの下から始まるようにします。
CSS変数で高さを一元管理する
ヘッダーの高さを変更するたびに複数箇所を修正するのは手間なので、CSS変数で管理すると便利です。
:root {
--header-height: 60px;
}
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: var(--header-height);
background: #fff;
z-index: 1000;
}
.main {
padding-top: var(--header-height);
}
position: sticky で追従ヘッダーを作る
position: sticky は、通常のフローに含まれたまま、スクロール時に指定位置で固定されるプロパティです。
.header {
position: sticky;
top: 0;
z-index: 1000;
background: #fff;
}
fixed との最大の違いは、コンテンツのずれが発生しないことです。sticky は通常フローに残るため、padding-top の調整が不要です。
fixed と sticky の違い
| 比較項目 | position: fixed | position: sticky |
|---|---|---|
| 基準 | ビューポート(画面全体) | 親要素のスクロール領域 |
| 通常フロー | 外れる(コンテンツがずれる) | 維持される(ずれない) |
| padding-top の調整 | 必要 | 不要 |
| 固定される範囲 | 常にビューポートに固定 | 親要素の範囲内で固定 |
| ブラウザ対応 | すべて | すべて(IE非対応) |
| おすすめの用途 | 常に画面に固定したいヘッダー | ページ内の特定セクションで固定 |
一般的なサイトのヘッダーには position: sticky が手軽でおすすめです。ただし、sticky が効かない場合は親要素に overflow: hidden が指定されていないか確認してください。
スクロール時に影を付ける
ヘッダーが固定されていることをユーザーに視覚的に伝えるため、スクロール時に影を付けるパターンがよく使われます。
JavaScript でスクロール位置を検知して影を付ける
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 60px;
background: #fff;
z-index: 1000;
transition: box-shadow 0.3s ease;
}
.header.scrolled {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
window.addEventListener('scroll', function() {
const header = document.querySelector('.header');
if (window.scrollY > 0) {
header.classList.add('scrolled');
} else {
header.classList.remove('scrolled');
}
});
半透明 + ぼかし効果(すりガラス風)
backdrop-filter を使うと、ヘッダーの背景をすりガラスのようにぼかすモダンなデザインが作れます。
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 60px;
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
z-index: 1000;
}
Apple のサイトなどで採用されているデザインです。背景を半透明にし、backdrop-filter: blur() で背後のコンテンツをぼかします。
上スクロールで表示・下スクロールで非表示にする
画面領域を有効活用するため、下にスクロールするとヘッダーが隠れ、上にスクロールすると再表示されるパターンが人気です。
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 60px;
background: #fff;
z-index: 1000;
transition: transform 0.3s ease;
}
.header.hidden {
transform: translateY(-100%);
}
let lastScrollY = 0;
window.addEventListener('scroll', function() {
const header = document.querySelector('.header');
const currentScrollY = window.scrollY;
if (currentScrollY > lastScrollY && currentScrollY > 60) {
// 下スクロール:ヘッダーを隠す
header.classList.add('hidden');
} else {
// 上スクロール:ヘッダーを表示
header.classList.remove('hidden');
}
lastScrollY = currentScrollY;
});
| 処理 | 説明 |
|---|---|
lastScrollY |
前回のスクロール位置を保持 |
currentScrollY > lastScrollY |
下方向にスクロールしたかを判定 |
currentScrollY > 60 |
ページ上部ではヘッダーを常に表示 |
translateY(-100%) |
ヘッダーを上方向に完全に移動して隠す |
transition: transform 0.3s |
表示・非表示をなめらかにアニメーション |
ちらつきを防ぐ(閾値の設定)
少しのスクロールでヘッダーが頻繁に出たり隠れたりするのを防ぐには、閾値(デッドゾーン)を設けます。
let lastScrollY = 0;
const THRESHOLD = 10; // 10px以上スクロールしたら反応
window.addEventListener('scroll', function() {
const header = document.querySelector('.header');
const currentScrollY = window.scrollY;
const diff = currentScrollY - lastScrollY;
if (diff > THRESHOLD && currentScrollY > 60) {
header.classList.add('hidden');
lastScrollY = currentScrollY;
} else if (diff < -THRESHOLD) {
header.classList.remove('hidden');
lastScrollY = currentScrollY;
}
});
スクロール時にヘッダーを縮小する
スクロール前は大きなヘッダー、スクロール後はコンパクトなヘッダーに切り替えるパターンです。
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 80px;
background: #fff;
z-index: 1000;
transition: height 0.3s ease, box-shadow 0.3s ease;
}
.header.compact {
height: 50px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.header .logo {
height: 40px;
transition: height 0.3s ease;
}
.header.compact .logo {
height: 28px;
}
window.addEventListener('scroll', function() {
const header = document.querySelector('.header');
if (window.scrollY > 100) {
header.classList.add('compact');
} else {
header.classList.remove('compact');
}
});
ロゴやナビゲーションのサイズも transition で一緒に変化させると、自然な動きになります。
z-index の管理
追従ヘッダーでは z-index の管理が重要です。ヘッダーが他の要素の下に隠れてしまう問題がよく発生します。
| 要素 | 推奨 z-index | 理由 |
|---|---|---|
| ヘッダー | 1000 |
ページ内のほとんどの要素より上に表示 |
| モーダル / ダイアログ | 2000 |
ヘッダーよりさらに上に表示 |
| トースト通知 | 3000 |
すべての要素の上に表示 |
z-index はスタッキングコンテキスト内でのみ比較されます。親要素に position: relative と z-index が指定されていると、新しいコンテキストが作られるため注意が必要です。
アンカーリンクの位置ずれを修正する
追従ヘッダーがあると、ページ内アンカーリンク(#section)でジャンプしたときに、ヘッダーの裏にコンテンツが隠れる問題が発生します。
/* 各セクションにスクロールマージンを設定 */
section {
scroll-margin-top: 70px; /* ヘッダー高さ + 余裕10px */
}
/* CSS変数を使う場合 */
section {
scroll-margin-top: calc(var(--header-height) + 10px);
}
scroll-margin-top はスクロール先の要素の上にマージンを確保するプロパティです。ヘッダーの高さ分を指定するだけで、アンカーリンクの位置ずれが解消されます。
レスポンシブ対応のポイント
| 考慮点 | 対応方法 |
|---|---|
| モバイルでヘッダーが大きすぎる | メディアクエリで高さを変更(PC: 80px → SP: 50px) |
| ナビメニューが入りきらない | ハンバーガーメニューに切り替える |
| ヘッダーの高さが変わると padding-top もずれる | CSS変数 + メディアクエリで一元管理 |
| モバイルで画面を圧迫する | 下スクロールで非表示にする |
:root {
--header-height: 80px;
}
@media (max-width: 768px) {
:root {
--header-height: 50px;
}
}
追従ヘッダーが効かないときのチェックリスト
| 症状 | 原因 | 対処法 |
|---|---|---|
| ヘッダーが他の要素の裏に隠れる | z-index が低い、またはスタッキングコンテキストの問題 |
z-index: 1000 を指定し、親要素の z-index を確認 |
| コンテンツがヘッダーの裏に隠れる | position: fixed でフローから外れている |
padding-top をヘッダーの高さ分追加 |
position: sticky が効かない |
親要素に overflow: hidden が指定されている |
親要素の overflow を visible に変更 |
| アンカーリンクの位置がずれる | ヘッダーの高さ分だけ対象がヘッダーの裏に入る | scroll-margin-top をヘッダーの高さ分指定 |
| ヘッダーの幅が画面いっぱいにならない | width: 100% が未指定 |
width: 100% と left: 0 を追加 |
まとめ
| パターン | 実装方法 | 特徴 |
|---|---|---|
| 常に固定 | position: fixed |
シンプル。padding-top の調整が必要 |
| 常に固定(モダン) | position: sticky |
padding-top 不要。親要素の overflow に注意 |
| スクロールで影 | JS でクラス切替 + box-shadow |
スクロール状態をユーザーに伝える |
| すりガラス風 | backdrop-filter: blur() |
モダンなデザイン |
| 上スクロールで表示 | JS でスクロール方向を検知 | 画面領域を有効活用 |
| スクロールで縮小 | JS でクラス切替 + transition |
ファーストビューと通常時で差をつける |
ポイント:
- 基本は
position: stickyが手軽でおすすめ position: fixedを使う場合はpadding-topでコンテンツのずれを防ぐ- CSS変数で高さを管理すると、レスポンシブ対応やアンカーリンク修正が楽になる
- 下スクロールで非表示にする場合は閾値(THRESHOLD)を設けてちらつきを防ぐ
- アンカーリンクの位置ずれは
scroll-margin-topで解決 z-indexは1000を目安に設定する

