【Next.js】スクロールで背景が変わる固定ヘッダーの作り方を解説
公開日: 2026年9月8日 · 読了目安 13 分
Next.js で、最初は透明でスクロールすると半透明の背景とぼかしが付く固定ヘッダーを作る手順です。sticky と fixed の選び方、16px の閾値でクラスを切り替えるコード、Liquid Glass 風の仕上げ、下スクロールで隠れるヘッダーまで解説します。
Next.js の固定ヘッダーをスクロールで変化させる方法
Next.js で LP を作り、ヒーローに写真や動きを入れた。
ところが上端の白いヘッダーバーがいつもヒーローを切ってしまい、古いコーポレートサイトのように見える。
そんなときは、ヘッダーの見た目をスクロール量で変えるのが近道です。
答えは次のとおりです。ページを開いた直後は、ヘッダーの背景を透明にしてヒーローを見せます。
16px ほどスクロールしたら、半透明の背景とぼかし(backdrop-blur)を付けます。
スクロールを読むのはヘッダーのファイルだけで、ページ全体をブラウザで動く部品(クライアントコンポーネント)にする必要はありません。
この記事で分かることは次のとおりです。
固定ヘッダーの土台に、2種類の固定のしかたのどちらを選ぶか
スクロールで背景とぼかしが変わるヘッダーバーのコード
Liquid Glass 風の半透明・ぼかし・角丸の島型に整える方法
下にスクロールすると隠れ、上に戻すと出てくるヘッダーの作り方
スクロールで変化する固定ヘッダーが LP に合う理由
ページを開いた瞬間から不透明のヘッダーバーがあると、ヒーローの上端はいつもその帯で隠れます。写真やアニメーションを見せたい LP では、最初の印象をヘッダーが削ってしまいます。
一方で、ヘッダーを透明のままにすると、本文に入ったときにリンクの文字が背景の写真や文章と重なって読めません。
最初は透明、スクロール後は半透明という切替は、この2つの問題を同時に解決します。
変化の幅は小さくて構いません。背景色・ぼかし・細い境界線が付くだけで、ナビゲーションが「ページの上に浮いた層」に見えるようになります。
ロゴの大きさや形まで変えると、かえって落ち着きがなくなります。
固定ヘッダーの土台:sticky と fixed の違い
上端に張り付くヘッダーは、2つの方法で作れます。position: sticky(スクロールしても止まって見える配置)と、position: fixed(画面に固定して浮かせる配置)です。
見た目は似ていますが、ヒーローとの重なり方が違います。
sticky: ヘッダーは自分の高さぶんの場所を取る。ヒーローはヘッダーの下から始まるので、透明にしてもヒーローの上には重ならない
fixed: ヘッダーは場所を取らず、ページの上に浮く。ヒーローの上に透明のヘッダーを重ねられるが、本文の先頭がヘッダーに隠れないよう余白が必要
止まって見える配置のまま重ねたい場合: ヒーローに -mt-16 のような負のマージンを付け、ヘッダーの高さぶん上に引き上げる
透明のヘッダーをヒーローの写真の上に乗せたいなら、浮かせる配置の fixed が素直です。
この記事では、この浮かせる配置を使います。ヒーロー以外のページでは、最初のセクションに pt-20 などの余白を付ける前提で進めます。
ヒーローとヘッダーを重ねない落ち着いたページなら、止まって見える配置でも問題ありません。
Step1:透明の固定ヘッダーを置く
まずはスクロール処理なしで、上端に固定された透明のヘッダーを置きます。この段階では、サーバーで組み立てる部品(サーバーコンポーネント)のままで構いません。
ポイントは3つです。
画面の上端に、左右いっぱいの幅で固定する(fixed と top-0 など)
最初から白い背景を付けない(付けると最初から帯になる)
重なり順を上げて、ヒーローより手前に出す(z-50)
export function SiteHeader() {
return (
<header className="fixed inset-x-0 top-0 z-50 px-6 py-4">
<div className="mx-auto flex max-w-6xl items-center justify-between">
<a href="/" className="text-sm font-semibold tracking-wide">
NORTHLINE
</a>
<nav className="hidden gap-8 text-sm md:flex">
<a href="#work">Work</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>
</nav>
</div>
</header>
);
}透明の固定ヘッダーだけで足りないもの
スクロールしても背景は透明のままです。本文に入ると、リンクの文字が下の内容と重なって読みにくくなります。
次の Step2 で、スクロール量に応じて背景を付けます。
Step2:スクロールでヘッダーバーの背景とぼかしを切り替える
やることの中心は1つです。スクロール量(window.scrollY)が閾値を超えたかどうかを、state(部品が覚えておく値)に持ちます。
その値に合わせて、透明用のクラスと半透明用のクラスを入れ替えます。
"use client";
import { useEffect, useState } from "react";
export function ScrollHeader() {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const onScroll = () => setScrolled(window.scrollY > 16);
onScroll(); // ページの途中で再読み込みした場合にも合わせる
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
return (
<header
className={
"fixed inset-x-0 top-0 z-50 transition-colors duration-300 " +
(scrolled
? "border-b border-zinc-200/60 bg-white/75 backdrop-blur-md"
: "border-b border-transparent bg-transparent")
}
>
<div className="mx-auto flex h-16 max-w-6xl items-center justify-between px-6">
<a href="/" className="text-sm font-semibold">
NORTHLINE
</a>
<nav className="hidden gap-8 text-sm md:flex">
<a href="#work">Work</a>
<a href="#about">About</a>
<a href="#contact">Contact</a>
</nav>
</div>
</header>
);
}固定ヘッダーのファイルだけをブラウザで動かす
ブラウザの window を読むので、"use client"(この部品はブラウザで動かす、という印)が必要です。ただし、付けるのはこのファイルだけです。
共通レイアウトの layout.tsx は、サーバーで組み立てる部品のままにします。そこに <ScrollHeader /> を置くだけで動きます。
レイアウト全体をブラウザで動かすと、ページ全体の JavaScript が増えてしまいます。
閾値は 16px から試す
1〜2px で切り替えると、トラックパッドの小さな揺れでヘッダーがちらつきます。
まずは 16px で試してください。ちらつくなら上げ、切替が遅いと感じたら下げます。
目安は8〜24ピクセルの範囲です。ヒーローの高さぶん待つ必要は通常ありません。
スクロールのたびに見た目を直接書き換えない
スクロールイベントのたびに element.style.backgroundColor を直接書き換える方法は、処理が増えてカクつきやすくなります。
上のコードのように「閾値を超えたか」だけを覚えておけば、再レンダリングは切替の瞬間の2回だけで済みます。
スクロールを見張る処理(リスナー)には { passive: true } を付けます。部品が画面から消えるときに、必ず外します。
ヘッダーで切り替えるものと固定するもの
切り替えてよいのは、次のものです。
背景色(透明と半透明)
背景のぼかしの有無
境界線
必要なら文字色
ロゴの形や大きさ、ナビの並び順は固定しておく方が安全です。スクロールでロゴが伸び縮みすると、ヘッダーより広告のように見えます。
Step3:Liquid Glass 風の島型ヘッダーに整える
Liquid Glass は、Apple がネイティブアプリのナビゲーションなどに使うガラスのような素材表現です。
Web には同じ仕組みがそのままあるわけではありません。ここでは次の要素を組み合わせて、近い見た目を作ります。
半透明の背景
背景のぼかし
文字の読みやすさ
左右に余白のある浮いた形
公式の再現ではなく、見た目の近似です。
<header className="fixed inset-x-0 top-0 z-50 px-4 pt-3">
<div
className={
"mx-auto flex h-14 max-w-5xl items-center justify-between rounded-full px-5 transition-all duration-300 " +
(scrolled
? "border border-white/40 bg-white/70 shadow-sm backdrop-blur-md"
: "border border-transparent")
}
>
{/* ロゴとナビは Step2 と同じ */}
</div>
</header>島型ヘッダーに見せるには外側に余白を残す
画面幅いっぱいのバーに角丸を付けても、島には見えません。外側の header に px-4 以上の余白を残し、内側の箱だけに背景・角丸・ぼかしを付けます。
影は shadow-sm 程度で足ります。影を強くしてガラス感を出そうとすると、くどい印象になります。
ぼかしは中くらいから試す
backdrop-blur は、Tailwind の backdrop-blur-md 前後から試してください。強くしすぎると、スマホでヘッダーだけ描画が重くなり、文字も霞みます。
白い背景のヒーローに白い文字を置いていないか、透明のときと半透明のときの両方で確認します。
ぼかしを二重に掛けない
ヒーロー側にも大きな半透明カードや強いぼかしがある場合、ヘッダーまで強くぼかすと画面全体が霞みます。どちらか一方を主役にし、ヘッダーは読めるガラスに留めます。
すりガラス風の表現そのものの作り方は https://design-layer.com/ja/articles/nextjs-glassmorphism-ui-guide で詳しく説明しています。
下スクロールで隠れて上に戻すと出るヘッダー
本文を読ませたいページでは、下にスクロールしている間はヘッダーを隠し、少しでも上に戻したら出す動きもよく使われます。前回のスクロール位置を ref(画面を描き直さずに値を覚えておく箱)に持ちます。
今の位置との差が下向きか上向きかで、隠す・出すを切り替えます。
"use client";
import { useEffect, useRef, useState } from "react";
export function AutoHideHeader() {
const [hidden, setHidden] = useState(false);
const [scrolled, setScrolled] = useState(false);
const lastY = useRef(0);
useEffect(() => {
lastY.current = window.scrollY;
const onScroll = () => {
const y = window.scrollY;
setScrolled(y > 16);
const diff = y - lastY.current;
if (Math.abs(diff) < 8) return; // 小さな揺れは無視する
setHidden(diff > 0 && y > 120); // 下向き、かつヒーローを過ぎたら隠す
lastY.current = y;
};
onScroll();
window.addEventListener("scroll", onScroll, { passive: true });
return () => window.removeEventListener("scroll", onScroll);
}, []);
return (
<header
className={
"fixed inset-x-0 top-0 z-50 transition duration-300 focus-within:translate-y-0 " +
(hidden ? "-translate-y-full" : "translate-y-0") +
(scrolled ? " bg-white/75 backdrop-blur-md" : "")
}
>
{/* ロゴとナビ */}
</header>
);
}隠れるヘッダーを使う場面を選ぶ
focus-within:translate-y-0 を付けているのは、Tab キーでリンクに移動したときに隠れたままにならないようにするためです。
ただし、スクロール連動のギャラリーのように大きく動くセクションがあるページでは、ヘッダーの出入りと動きがぶつかります。
LP では隠さずに薄く残す方が無難なことが多いです。
固定ヘッダーを公開する前の確認リスト
透明のときと半透明のときの両方で、ロゴとリンクが読めるか
ページ内リンクで移動したとき、見出しがヘッダーに隠れないか。html に scroll-padding-top を付けるか、見出しに scroll-mt-20 を付ける
ページの途中で再読み込みしても、ヘッダーの状態が正しいか
キーボードでリンクをたどったとき、フォーカスの枠が見えるか
スマホでぼかしが重すぎないか、リンクがタップしやすい大きさか
浮かせる配置にしたとき、ヒーロー以外のページで先頭の内容がヘッダーの下に潜っていないか
スマホのナビゲーションは、PC と同じリンクをそのまま詰め込むより、ハンバーガーメニューにまとめる方が扱いやすくなります。開閉の動きは https://design-layer.com/ja/articles/nextjs-mobile-nav-animation-guide で解説しています。
完成した固定ヘッダーをコピーして使う方法

自分で Step1 と Step2 を書いたうえで、島型やガラス風の完成したヘッダーを見比べてから決めたい場合もあります。
そのときは、DesignLayer のカタログで実際に動かして確認できます。ライブプレビューでスクロール時の変化を見て、Copy for Cursor で React と Tailwind のコードを AI エージェントに渡す流れです。
閲覧にカードは不要で、無料のソースコピーは日本時間で1日3回です。カタログは https://design-layer.com/ja/components から開けます。
向いているのは、LP・ポートフォリオ・製品紹介ページの上端です。多階層のドキュメントナビや、ログイン後のアプリのバーは、素のリンクで作る方が早いことが多いです。
固定ヘッダーについてよくある質問
はい。スクロール量を読むヘッダーのファイルにだけ、ブラウザで動かす印の "use client" を付けます。
透明の固定ヘッダーだけなら、サーバーで組み立てる部品のままで作れます。
まとめ:スクロールで変わる固定ヘッダーの作り方
Next.js の固定ヘッダーは、最初は透明にし、少しスクロールしたら半透明とぼかしを付ける
ヒーローの上に重ねるなら浮かせる配置、重ねないなら止まって見える配置を選ぶ
「スクロールしたかどうか」だけを覚えて、Tailwind のクラスを入れ替える
Liquid Glass 風は、半透明・背景のぼかし・外側の余白で近づける
ページ内リンクで見出しが隠れないか、キーボード操作の枠が見えるかを確認する
まずは Step2 のコードを自分の layout.tsx に置いて、ヒーローとの重なり方を確かめてください。ヘッダーの下に置くヒーローの作り方は https://design-layer.com/ja/articles/nextjs-animated-hero-section-guide で解説しています。


