全画面オーバーレイメニュー
ハンバーガーをタップすると全画面メニューが開き、リンクが時間差で迫り上がる演出。アイコンはX字へモーフ。ポートフォリオやブランドサイトのモバイル導線に効く没入型ナビです。
ライブデモ
使用例(お題: アイドルグループ Sakura)
この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- Sakura:アイドル公式サイトの全画面メニュー -->
<div class="hfo-frame" id="hfoFrame">
<header class="hfo-head">
<a class="hfo-logo" href="#" onclick="return false">SAKURA</a>
<button class="hfo-burger" id="hfoBurger" type="button" aria-label="メニュー" aria-expanded="false">
<span></span><span></span><span></span>
</button>
</header>
<nav class="hfo-overlay" id="hfoOverlay" aria-hidden="true">
<ul class="hfo-list">
<li style="--i:0"><a href="#" onclick="return false">News</a></li>
<li style="--i:1"><a href="#" onclick="return false">Live</a></li>
<li style="--i:2"><a href="#" onclick="return false">Member</a></li>
<li style="--i:3"><a href="#" onclick="return false">Movie</a></li>
</ul>
<p class="hfo-meta">2nd LIVE TOUR「星降る夜の桜物語」開催決定</p>
</nav>
<div class="hfo-stage">
<h1>満開の、その先へ</h1>
<p>右上のボタンで全画面メニューが開きます。</p>
</div>
</div>
CSS
/* Sakura(アイドル):全画面オーバーレイメニューの再スキン */
* { box-sizing: border-box; }
body { margin: 0; font-family: "Hiragino Kaku Gothic ProN", "Segoe UI", system-ui, sans-serif; }
.hfo-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #1a0f1e; }
.hfo-head { position: absolute; top: 0; left: 0; right: 0; z-index: 30; display: flex; align-items: center; justify-content: space-between; height: 58px; padding: 0 22px; }
.hfo-logo { font-size: 16px; font-weight: 800; letter-spacing: .28em; color: #ffd9e8; text-decoration: none; }
.hfo-burger { width: 40px; height: 40px; position: relative; background: none; border: none; cursor: pointer; padding: 0; }
.hfo-burger span { position: absolute; left: 9px; right: 9px; height: 2px; background: #ffd9e8; border-radius: 2px; transition: transform .35s ease, opacity .25s ease; }
.hfo-burger span:nth-child(1) { top: 14px; }
.hfo-burger span:nth-child(2) { top: 19px; }
.hfo-burger span:nth-child(3) { top: 24px; }
.hfo-frame.is-open .hfo-burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.hfo-frame.is-open .hfo-burger span:nth-child(2) { opacity: 0; }
.hfo-frame.is-open .hfo-burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
.hfo-overlay {
position: absolute; inset: 0; z-index: 20;
display: flex; flex-direction: column; justify-content: center; gap: 4px; padding: 0 40px;
background: linear-gradient(150deg, #d6336c 0%, #7048e8 100%);
clip-path: circle(0% at calc(100% - 38px) 30px);
transition: clip-path .5s cubic-bezier(.86,0,.07,1);
}
.hfo-frame.is-open .hfo-overlay { clip-path: circle(150% at calc(100% - 38px) 30px); }
.hfo-list { list-style: none; margin: 0; padding: 0; }
.hfo-list li { opacity: 0; transform: translateY(24px); transition: opacity .4s ease, transform .4s ease; transition-delay: calc(var(--i) * 70ms); }
.hfo-frame.is-open .hfo-list li { opacity: 1; transform: translateY(0); }
.hfo-list a { color: #fff; text-decoration: none; font-size: 34px; font-weight: 800; letter-spacing: -.01em; line-height: 1.45; }
.hfo-list a:hover { opacity: .82; }
.hfo-meta { margin: 22px 0 0; color: rgba(255,255,255,.85); font-size: 12px; letter-spacing: .04em; opacity: 0; transition: opacity .4s ease .35s; }
.hfo-frame.is-open .hfo-meta { opacity: 1; }
.hfo-stage { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; color: #ffe3ee; padding: 0 24px; }
.hfo-stage h1 { margin: 0; font-size: 28px; font-weight: 800; }
.hfo-stage p { margin: 10px 0 0; font-size: 13px; opacity: .7; }
@media (prefers-reduced-motion: reduce) { .hfo-overlay, .hfo-list li, .hfo-burger span, .hfo-meta { transition: none; } }
JavaScript
// (デモと同じフックを流用)ハンバーガーで全画面メニュー開閉+自動実演
(() => {
const frame = document.getElementById('hfoFrame');
const burger = document.getElementById('hfoBurger');
const overlay = document.getElementById('hfoOverlay');
if (!frame || !burger || !overlay) return;
const set = (open) => {
frame.classList.toggle('is-open', open);
burger.setAttribute('aria-expanded', open ? 'true' : 'false');
overlay.setAttribute('aria-hidden', open ? 'false' : 'true');
};
let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches;
burger.addEventListener('click', () => { auto = false; set(!frame.classList.contains('is-open')); });
if (auto) {
let open = false;
const tick = () => { if (!auto) return; open = !open; set(open); setTimeout(tick, open ? 2600 : 1600); };
setTimeout(tick, 1100);
}
})();
実装ガイド
使いどころ
ポートフォリオ・ブランド・アイドルなど世界観重視のサイトのモバイル導線に。ハンバーガーをタップすると全画面メニューが円形に広がり、リンクが時間差で迫り上がります。
実装時の注意点
オーバーレイの開閉は clip-path: circle() のアニメーションで、ボタン位置を中心に広がります。リンクは --i を使った transition-delay で順次フェードアップ。ハンバーガーは3本線が CSS transform で X 字へモーフします。is-open クラスをフレームに付けるだけで全要素が連動します。
対応ブラウザ
clip-path: circle()・transform・transition は全モダンブラウザで対応します。clip-path の円形アニメーションは GPU 合成に乗り軽量です。
よくある失敗
オーバーレイ表示中は背面スクロールを止める(body 側の overflow:hidden)配慮が実サイトでは必要です。メニューを開いたら最初のリンクへフォーカス移動し、Esc とフォーカストラップを用意するとアクセシブル。clip-path の中心座標はボタン位置と一致させないと展開が不自然になります。
応用例
背景に画像や動画を敷く、リンクのホバーで大きな矢印やサムネを出す、開閉のイージングを変えて印象を調整する、SNSリンクや言語切替を下部に添えるなどの発展があります。
コード
HTML
<!-- ハンバーガー → 全画面オーバーレイメニュー -->
<div class="hfo-frame" id="hfoFrame">
<header class="hfo-head">
<a class="hfo-logo" href="#" onclick="return false">STUDIO N</a>
<button class="hfo-burger" id="hfoBurger" type="button" aria-label="メニュー" aria-expanded="false">
<span></span><span></span><span></span>
</button>
</header>
<!-- 全画面メニュー -->
<nav class="hfo-overlay" id="hfoOverlay" aria-hidden="true">
<ul class="hfo-list">
<li style="--i:0"><a href="#" onclick="return false">Works</a></li>
<li style="--i:1"><a href="#" onclick="return false">About</a></li>
<li style="--i:2"><a href="#" onclick="return false">Journal</a></li>
<li style="--i:3"><a href="#" onclick="return false">Contact</a></li>
</ul>
<p class="hfo-meta">hello@studio-n.jp / Tokyo</p>
</nav>
<div class="hfo-stage">
<h1>没入型の全画面ナビ</h1>
<p>右上のボタンで開閉。リンクが時間差で迫り上がります。</p>
</div>
</div>
CSS
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }
.hfo-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #101014; }
.hfo-head {
position: absolute; top: 0; left: 0; right: 0; z-index: 30;
display: flex; align-items: center; justify-content: space-between;
height: 58px; padding: 0 22px;
}
.hfo-logo { font-size: 16px; font-weight: 800; letter-spacing: .22em; color: #fff; text-decoration: none; }
/* ハンバーガー → X */
.hfo-burger { width: 40px; height: 40px; position: relative; background: none; border: none; cursor: pointer; padding: 0; }
.hfo-burger span {
position: absolute; left: 9px; right: 9px; height: 2px; background: #fff; border-radius: 2px;
transition: transform .35s ease, opacity .25s ease;
}
.hfo-burger span:nth-child(1) { top: 14px; }
.hfo-burger span:nth-child(2) { top: 19px; }
.hfo-burger span:nth-child(3) { top: 24px; }
.hfo-frame.is-open .hfo-burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.hfo-frame.is-open .hfo-burger span:nth-child(2) { opacity: 0; }
.hfo-frame.is-open .hfo-burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
/* オーバーレイ */
.hfo-overlay {
position: absolute; inset: 0; z-index: 20;
display: flex; flex-direction: column; justify-content: center; gap: 4px;
padding: 0 40px;
background: linear-gradient(150deg, #4f46e5 0%, #db2777 100%);
clip-path: circle(0% at calc(100% - 38px) 30px);
transition: clip-path .5s cubic-bezier(.86, 0, .07, 1);
}
.hfo-frame.is-open .hfo-overlay { clip-path: circle(150% at calc(100% - 38px) 30px); }
.hfo-list { list-style: none; margin: 0; padding: 0; }
.hfo-list li {
opacity: 0; transform: translateY(24px);
transition: opacity .4s ease, transform .4s ease;
transition-delay: calc(var(--i) * 70ms);
}
.hfo-frame.is-open .hfo-list li { opacity: 1; transform: translateY(0); }
.hfo-list a { color: #fff; text-decoration: none; font-size: 34px; font-weight: 800; letter-spacing: -.01em; line-height: 1.45; }
.hfo-list a:hover { opacity: .8; }
.hfo-meta { margin: 22px 0 0; color: rgba(255,255,255,.8); font-size: 12px; letter-spacing: .06em; opacity: 0; transition: opacity .4s ease .35s; }
.hfo-frame.is-open .hfo-meta { opacity: 1; }
.hfo-stage { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; color: #fff; padding: 0 24px; }
.hfo-stage h1 { margin: 0; font-size: 26px; font-weight: 800; }
.hfo-stage p { margin: 10px 0 0; font-size: 13px; opacity: .65; }
@media (prefers-reduced-motion: reduce) {
.hfo-overlay, .hfo-list li, .hfo-burger span, .hfo-meta { transition: none; }
}
JavaScript
// ハンバーガーで全画面メニューを開閉。プレビューでは自動でも開閉する
(() => {
const frame = document.getElementById('hfoFrame');
const burger = document.getElementById('hfoBurger');
const overlay = document.getElementById('hfoOverlay');
if (!frame || !burger || !overlay) return;
const set = (open) => {
frame.classList.toggle('is-open', open);
burger.setAttribute('aria-expanded', open ? 'true' : 'false');
overlay.setAttribute('aria-hidden', open ? 'false' : 'true');
};
let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches;
burger.addEventListener('click', () => {
auto = false;
set(!frame.classList.contains('is-open'));
});
// 自動デモ:開く→閉じるを繰り返す
if (auto) {
let open = false;
const tick = () => {
if (!auto) return;
open = !open;
set(open);
setTimeout(tick, open ? 2600 : 1600);
};
setTimeout(tick, 1100);
}
})();
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「全画面オーバーレイメニュー」の効果を追加してください。
# 追加してほしい効果
全画面オーバーレイメニュー(ヘッダー)
ハンバーガーをタップすると全画面メニューが開き、リンクが時間差で迫り上がる演出。アイコンはX字へモーフ。ポートフォリオやブランドサイトのモバイル導線に効く没入型ナビです。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- ハンバーガー → 全画面オーバーレイメニュー -->
<div class="hfo-frame" id="hfoFrame">
<header class="hfo-head">
<a class="hfo-logo" href="#" onclick="return false">STUDIO N</a>
<button class="hfo-burger" id="hfoBurger" type="button" aria-label="メニュー" aria-expanded="false">
<span></span><span></span><span></span>
</button>
</header>
<!-- 全画面メニュー -->
<nav class="hfo-overlay" id="hfoOverlay" aria-hidden="true">
<ul class="hfo-list">
<li style="--i:0"><a href="#" onclick="return false">Works</a></li>
<li style="--i:1"><a href="#" onclick="return false">About</a></li>
<li style="--i:2"><a href="#" onclick="return false">Journal</a></li>
<li style="--i:3"><a href="#" onclick="return false">Contact</a></li>
</ul>
<p class="hfo-meta">hello@studio-n.jp / Tokyo</p>
</nav>
<div class="hfo-stage">
<h1>没入型の全画面ナビ</h1>
<p>右上のボタンで開閉。リンクが時間差で迫り上がります。</p>
</div>
</div>
【CSS】
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }
.hfo-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #101014; }
.hfo-head {
position: absolute; top: 0; left: 0; right: 0; z-index: 30;
display: flex; align-items: center; justify-content: space-between;
height: 58px; padding: 0 22px;
}
.hfo-logo { font-size: 16px; font-weight: 800; letter-spacing: .22em; color: #fff; text-decoration: none; }
/* ハンバーガー → X */
.hfo-burger { width: 40px; height: 40px; position: relative; background: none; border: none; cursor: pointer; padding: 0; }
.hfo-burger span {
position: absolute; left: 9px; right: 9px; height: 2px; background: #fff; border-radius: 2px;
transition: transform .35s ease, opacity .25s ease;
}
.hfo-burger span:nth-child(1) { top: 14px; }
.hfo-burger span:nth-child(2) { top: 19px; }
.hfo-burger span:nth-child(3) { top: 24px; }
.hfo-frame.is-open .hfo-burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.hfo-frame.is-open .hfo-burger span:nth-child(2) { opacity: 0; }
.hfo-frame.is-open .hfo-burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
/* オーバーレイ */
.hfo-overlay {
position: absolute; inset: 0; z-index: 20;
display: flex; flex-direction: column; justify-content: center; gap: 4px;
padding: 0 40px;
background: linear-gradient(150deg, #4f46e5 0%, #db2777 100%);
clip-path: circle(0% at calc(100% - 38px) 30px);
transition: clip-path .5s cubic-bezier(.86, 0, .07, 1);
}
.hfo-frame.is-open .hfo-overlay { clip-path: circle(150% at calc(100% - 38px) 30px); }
.hfo-list { list-style: none; margin: 0; padding: 0; }
.hfo-list li {
opacity: 0; transform: translateY(24px);
transition: opacity .4s ease, transform .4s ease;
transition-delay: calc(var(--i) * 70ms);
}
.hfo-frame.is-open .hfo-list li { opacity: 1; transform: translateY(0); }
.hfo-list a { color: #fff; text-decoration: none; font-size: 34px; font-weight: 800; letter-spacing: -.01em; line-height: 1.45; }
.hfo-list a:hover { opacity: .8; }
.hfo-meta { margin: 22px 0 0; color: rgba(255,255,255,.8); font-size: 12px; letter-spacing: .06em; opacity: 0; transition: opacity .4s ease .35s; }
.hfo-frame.is-open .hfo-meta { opacity: 1; }
.hfo-stage { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; color: #fff; padding: 0 24px; }
.hfo-stage h1 { margin: 0; font-size: 26px; font-weight: 800; }
.hfo-stage p { margin: 10px 0 0; font-size: 13px; opacity: .65; }
@media (prefers-reduced-motion: reduce) {
.hfo-overlay, .hfo-list li, .hfo-burger span, .hfo-meta { transition: none; }
}
【JavaScript】
// ハンバーガーで全画面メニューを開閉。プレビューでは自動でも開閉する
(() => {
const frame = document.getElementById('hfoFrame');
const burger = document.getElementById('hfoBurger');
const overlay = document.getElementById('hfoOverlay');
if (!frame || !burger || !overlay) return;
const set = (open) => {
frame.classList.toggle('is-open', open);
burger.setAttribute('aria-expanded', open ? 'true' : 'false');
overlay.setAttribute('aria-hidden', open ? 'false' : 'true');
};
let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches;
burger.addEventListener('click', () => {
auto = false;
set(!frame.classList.contains('is-open'));
});
// 自動デモ:開く→閉じるを繰り返す
if (auto) {
let open = false;
const tick = () => {
if (!auto) return;
open = !open;
set(open);
setTimeout(tick, open ? 2600 : 1600);
};
setTimeout(tick, 1100);
}
})();
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。