DEMO
下へスクロールすると、ヘッダーが縮んで背景がすりガラスになります。
CODE
<div class="demo-stage shh-stage">
<div class="shh-scroller" id="shh-scroller" tabindex="0" aria-label="縮むヘッダーのデモ(スクロールしてください)">
<header class="shh-header" id="shh-header">
<div class="shh-inner"><span class="shh-logo">MOTION</span><nav class="shh-nav"><a href="#" onclick="return false">Docs</a><a href="#" onclick="return false">Blog</a></nav></div>
</header>
<div class="shh-sentinel" id="shh-sentinel" aria-hidden="true"></div>
<div class="shh-body">
<p>下へスクロールすると、ヘッダーが縮んで背景がすりガラスになります。</p>
<div class="shh-card"></div><div class="shh-card"></div><div class="shh-card"></div><div class="shh-card"></div>
</div>
</div>
</div>
.shh-stage { display:flex; align-items:center; justify-content:center; padding:1.5rem; background:#0B0B10; min-height:300px; }
.shh-scroller { position:relative; width:100%; max-width:440px; height:270px; overflow-y:auto; border-radius:14px; border:1px solid rgba(255,255,255,.1); background:linear-gradient(180deg,#2B1040 0%,#15151B 45%); }
.shh-scroller:focus-visible { outline:2px solid #E91B89; outline-offset:3px; }
.shh-header { position:sticky; top:0; z-index:2; height:72px; margin-bottom:-72px; }
.shh-header::before {
content:''; position:absolute; inset:0; background:rgba(21,21,27,.72); backdrop-filter:blur(10px);
border-bottom:1px solid rgba(255,255,255,.1); opacity:0; transform:scaleY(.62); transform-origin:top;
transition: opacity .3s ease, transform .3s cubic-bezier(.22,1,.36,1);
}
.shh-inner { position:relative; height:72px; display:flex; align-items:center; justify-content:space-between; padding:0 1.2rem; transform-origin:top; transition: transform .3s cubic-bezier(.22,1,.36,1); }
.shh-logo { font-family:'Oswald',sans-serif; color:#fff; font-size:1.3rem; letter-spacing:.2em; transform-origin:left center; transition: transform .3s cubic-bezier(.22,1,.36,1); }
.shh-nav { display:flex; gap:1rem; }
.shh-nav a { color:#C9C9D1; font-size:.8rem; text-decoration:none; }
.shh-nav a:focus-visible { outline:2px solid #E91B89; outline-offset:2px; }
.shh-header.is-shrunk::before { opacity:1; transform:scaleY(.62); }
.shh-header.is-shrunk .shh-inner { transform:translateY(-14px); }
.shh-header.is-shrunk .shh-logo { transform:scale(.8); }
.shh-sentinel { height:1px; }
.shh-body { padding:92px 1.2rem 1.2rem; }
.shh-body p { margin:0 0 1rem; color:#C9C9D1; font-size:.85rem; }
.shh-card { height:70px; margin-bottom:.8rem; border-radius:10px; background:rgba(255,255,255,.07); }
@media (prefers-reduced-motion: reduce) {
.shh-header::before, .shh-inner, .shh-logo { transition-duration:.01ms; }
}
(function(){
var sc = document.getElementById('shh-scroller');
var header = document.getElementById('shh-header');
var sentinel = document.getElementById('shh-sentinel');
if (!sc || !header || !sentinel) return;
if (!('IntersectionObserver' in window)) {
sc.addEventListener('scroll', function(){ header.classList.toggle('is-shrunk', sc.scrollTop > 8); }, { passive: true });
return;
}
new IntersectionObserver(function(entries){
header.classList.toggle('is-shrunk', !entries[0].isIntersecting);
}, { root: sc, threshold: 0 }).observe(sentinel);
})();
AI PROMPT
スクロールを始めると高さが縮み、背景がすりガラスに変わる固定ヘッダーを作って。ヘッダーは position: sticky; top: 0。縮む判定は scroll イベントではなく、ヘッダー直下に置いた高さ1pxの見えない要素(sentinel)を IntersectionObserver で監視し、画面から外れたら .is-shrunk を付ける(毎フレームの計算が要らない)。縮める時は height を変えずに transform で動かすこと:背景は ::before に置いて transform: scaleY(.62)(transform-origin: top)、中身は translateY(-14px)、ロゴは scale(.8)。背景色は半透明+backdrop-filter: blur(10px) で下のコンテンツが透ける質感にする。IntersectionObserver が無い環境では scroll イベント(passive)で代替する。@media (prefers-reduced-motion: reduce) で transition を .01ms にする。 Acceptance criteria: works with prefers-reduced-motion (animation disabled), zero console errors, zero layout shift
AIエージェントでの実装ガイド → Claude Code でWebアニメーションを実装する
BOOKS · PR · AMAZON
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
学びを止めない · AMAZONサブスク
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
ページの先頭では大きく表示し、スクロールを始めると高さを詰めて画面を広く使えるようにする固定ヘッダーです。ロゴやナビゲーションを常に見せたいが、読んでいる本文の面積も確保したい、という両立のための定番の作りです。
当サイトの Sticky Sections はセクションが積み重なるスクロール演出、Hamburger Menu はメニューの開閉です。本ページはヘッダー自身がスクロール位置に応じて姿を変える別テーマで、コーポレートサイトやメディアのヘッダーにそのまま使えます。
要点は、縮む判定を軽くすることと、レイアウトを動かさないことの2つです。IntersectionObserver と transform の組み合わせにすると、スクロールが重いページでもヘッダーの切り替えがカクつきません。
height を直接変えずに transform で縮めるのはなぜですか?
height を変えるとヘッダーの下にある本文全体の位置が再計算され、スクロール中に本文がガクッと動く原因になります。背景を疑似要素に分けて scaleY で縮め、中身は translateY で上へずらすと、レイアウトは一切変わらずに見た目だけが縮みます。
scroll イベントではなく IntersectionObserver を使う理由は?
scroll イベントはスクロール中に何十回も発火し、毎回位置を読むとメインスレッドを圧迫します。見えない sentinel 要素が画面から外れた瞬間だけ通知される IntersectionObserver なら、判定は状態が変わる2回だけで済みます。
コードは無料で使えますか?
はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。