小型ドロップダウンナビ
メガメニューほど大きくない、項目ごとの小さなドロップダウン。ホバー/フォーカスで数件のサブリンクをふわっと出します。情報量が中程度のサイトでちょうどよい、扱いやすいナビです。
ライブデモ
使用例(お題: カフェ MOON BREW)
この技法を「カフェ MOON BREW」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- MOON BREW:カフェの小型ドロップダウンナビ -->
<div class="hdm-frame">
<header class="hdm-head">
<a class="hdm-logo" href="#" onclick="return false">☕ MOON BREW</a>
<nav class="hdm-nav">
<div class="hdm-item" id="hdmItem">
<button class="hdm-trigger" type="button" aria-expanded="false">メニュー <span class="hdm-caret">▾</span></button>
<div class="hdm-menu" role="menu">
<a href="#" onclick="return false">コーヒー</a>
<a href="#" onclick="return false">ラテ・カフェオレ</a>
<a href="#" onclick="return false">フード</a>
</div>
</div>
<a class="hdm-link" href="#" onclick="return false">豆を買う</a>
<a class="hdm-link" href="#" onclick="return false">店舗</a>
<a class="hdm-link" href="#" onclick="return false">物語</a>
</nav>
<button class="hdm-cta" type="button">予約する</button>
</header>
<div class="hdm-stage">
<h1>夜にひらく、珈琲店</h1>
<p>「メニュー」にホバー/フォーカスで小さな下層メニュー。</p>
</div>
</div>
CSS
/* MOON BREW(カフェ):小型ドロップダウンナビの再スキン */
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }
.hdm-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #f7f2e9; }
.hdm-head { position: relative; z-index: 5; display: flex; align-items: center; gap: 20px; height: 60px; padding: 0 24px; background: #fffdf8; border-bottom: 1px solid #ece2d0; }
.hdm-logo { font-size: 18px; font-weight: 800; color: #7a4f2a; text-decoration: none; }
.hdm-nav { display: flex; align-items: center; gap: 4px; }
.hdm-trigger, .hdm-link { font: inherit; font-size: 13.5px; font-weight: 600; color: #5b4630; background: none; border: none; cursor: pointer; text-decoration: none; padding: 8px 12px; border-radius: 8px; display: inline-flex; align-items: center; gap: 5px; transition: background .2s ease, color .2s ease; }
.hdm-trigger:hover, .hdm-link:hover { background: #f1e7d6; color: #7a4f2a; }
.hdm-caret { font-size: 9px; transition: transform .25s ease; }
.hdm-cta { margin-left: auto; font: inherit; font-size: 12.5px; font-weight: 700; color: #fff; background: #7a4f2a; border: none; padding: 9px 17px; border-radius: 999px; cursor: pointer; transition: filter .15s ease, transform .15s ease; }
.hdm-cta:hover { filter: brightness(1.08); transform: translateY(-1px); }
.hdm-item { position: relative; }
.hdm-menu { position: absolute; top: calc(100% + 6px); left: 0; min-width: 178px; background: #fffdf8; border: 1px solid #ece2d0; border-radius: 11px; padding: 6px; box-shadow: 0 16px 34px rgba(90,60,30,.16); opacity: 0; transform: translateY(-6px); pointer-events: none; transition: opacity .2s ease, transform .2s ease; }
.hdm-item:hover .hdm-menu, .hdm-item:focus-within .hdm-menu, .hdm-item.is-open .hdm-menu { opacity: 1; transform: translateY(0); pointer-events: auto; }
.hdm-item:hover .hdm-caret, .hdm-item.is-open .hdm-caret { transform: rotate(180deg); }
.hdm-menu a { display: block; font-size: 13px; color: #5b4630; text-decoration: none; padding: 9px 11px; border-radius: 8px; transition: background .16s ease; }
.hdm-menu a:hover { background: #f3ead9; color: #7a4f2a; }
.hdm-stage { display: grid; place-content: center; height: calc(100% - 60px); text-align: center; color: #4a3320; padding: 0 24px; }
.hdm-stage h1 { margin: 0; font-size: 26px; font-weight: 800; font-family: "Hiragino Mincho ProN", serif; }
.hdm-stage p { margin: 12px 0 0; font-size: 13px; line-height: 1.8; color: #8a715a; }
@media (prefers-reduced-motion: reduce) { .hdm-menu, .hdm-caret, .hdm-cta { transition: none; } }
JavaScript
// (デモと同じフックを流用)ホバー/フォーカス+自動開閉で小型ドロップダウン
(() => {
const item = document.getElementById('hdmItem');
if (!item) return;
const trigger = item.querySelector('.hdm-trigger');
const sync = () => trigger && trigger.setAttribute('aria-expanded', item.classList.contains('is-open') ? 'true' : 'false');
let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches;
['pointerenter', 'focusin', 'pointerdown'].forEach(ev => item.addEventListener(ev, () => { auto = false; item.classList.remove('is-open'); sync(); }));
if (auto) {
let open = false;
const tick = () => { if (!auto) return; open = !open; item.classList.toggle('is-open', open); sync(); setTimeout(tick, open ? 2000 : 1400); };
setTimeout(tick, 1000);
}
})();
実装ガイド
使いどころ
情報量が中程度のサイトで、メガメニューほど大げさにせず数件のサブリンクを見せたいときに。項目ごとの小さなドロップダウンです。
実装時の注意点
開閉は :hover と :focus-within(CSS)で行い、JS はプレビュー用の自動開閉のみ。パネルは項目基準の絶対配置で、ふわっとフェード+スライドして開きます。
対応ブラウザ
:focus-within・transition は全モダンブラウザ対応。キーボード操作にも反応します。
よくある失敗
ホバーのみだとタッチで使えないため、クリック/タップのフォールバックを。画面端の項目はパネルが切れないよう右寄せに切り替える配慮を。ホバーインテント(遅延)が無いと通過しただけで開いて煩わしくなります。
応用例
アイコン付きリンク、2カラム化、選択中のハイライト、矢印キーでの項目移動などに拡張できます。
コード
HTML
<!-- 項目ごとの小型ドロップダウンナビ -->
<div class="hdm-frame">
<header class="hdm-head">
<a class="hdm-logo" href="#" onclick="return false">Pine</a>
<nav class="hdm-nav">
<div class="hdm-item" id="hdmItem">
<button class="hdm-trigger" type="button" aria-expanded="false">サービス <span class="hdm-caret">▾</span></button>
<div class="hdm-menu" role="menu">
<a href="#" onclick="return false">サイト制作</a>
<a href="#" onclick="return false">運用・保守</a>
<a href="#" onclick="return false">アクセス解析</a>
</div>
</div>
<a class="hdm-link" href="#" onclick="return false">料金</a>
<a class="hdm-link" href="#" onclick="return false">実績</a>
<a class="hdm-link" href="#" onclick="return false">会社</a>
</nav>
<button class="hdm-cta" type="button">相談する</button>
</header>
<div class="hdm-stage">
<h1>小型ドロップダウン</h1>
<p>「サービス」にホバー/フォーカスで小さな下層メニュー。<br>(自動でも開閉を実演します)</p>
</div>
</div>
CSS
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }
.hdm-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #f3f6f4; }
.hdm-head { position: relative; z-index: 5; display: flex; align-items: center; gap: 20px; height: 60px; padding: 0 24px; background: #fff; border-bottom: 1px solid #e4ebe6; }
.hdm-logo { font-size: 19px; font-weight: 800; color: #15803d; text-decoration: none; }
.hdm-nav { display: flex; align-items: center; gap: 4px; }
.hdm-trigger, .hdm-link { font: inherit; font-size: 13.5px; font-weight: 600; color: #2f4137; background: none; border: none; cursor: pointer; text-decoration: none; padding: 8px 12px; border-radius: 8px; display: inline-flex; align-items: center; gap: 5px; transition: background .2s ease, color .2s ease; }
.hdm-trigger:hover, .hdm-link:hover { background: #e7f3eb; color: #15803d; }
.hdm-caret { font-size: 9px; transition: transform .25s ease; }
.hdm-cta { margin-left: auto; font: inherit; font-size: 12.5px; font-weight: 700; color: #fff; background: #15803d; border: none; padding: 9px 17px; border-radius: 999px; cursor: pointer; transition: filter .15s ease, transform .15s ease; }
.hdm-cta:hover { filter: brightness(1.08); transform: translateY(-1px); }
/* 小型ドロップダウン */
.hdm-item { position: relative; }
.hdm-menu {
position: absolute; top: calc(100% + 6px); left: 0; min-width: 168px;
background: #fff; border: 1px solid #e2e8e4; border-radius: 11px; padding: 6px;
box-shadow: 0 16px 34px rgba(20,40,28,.14);
opacity: 0; transform: translateY(-6px); pointer-events: none;
transition: opacity .2s ease, transform .2s ease;
}
.hdm-item:hover .hdm-menu, .hdm-item:focus-within .hdm-menu, .hdm-item.is-open .hdm-menu { opacity: 1; transform: translateY(0); pointer-events: auto; }
.hdm-item:hover .hdm-caret, .hdm-item.is-open .hdm-caret { transform: rotate(180deg); }
.hdm-menu a { display: block; font-size: 13px; color: #2f4137; text-decoration: none; padding: 9px 11px; border-radius: 8px; transition: background .16s ease; }
.hdm-menu a:hover { background: #eef6f0; color: #15803d; }
.hdm-stage { display: grid; place-content: center; height: calc(100% - 60px); text-align: center; color: #243029; padding: 0 24px; }
.hdm-stage h1 { margin: 0; font-size: 26px; font-weight: 800; }
.hdm-stage p { margin: 12px 0 0; font-size: 13px; line-height: 1.8; color: #5d6f63; }
@media (prefers-reduced-motion: reduce) { .hdm-menu, .hdm-caret, .hdm-cta { transition: none; } }
JavaScript
// ホバー/フォーカス+自動開閉で小型ドロップダウンを実演
(() => {
const item = document.getElementById('hdmItem');
if (!item) return;
const trigger = item.querySelector('.hdm-trigger');
const sync = () => trigger && trigger.setAttribute('aria-expanded', item.classList.contains('is-open') ? 'true' : 'false');
let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches;
['pointerenter', 'focusin', 'pointerdown'].forEach(ev => item.addEventListener(ev, () => { auto = false; item.classList.remove('is-open'); sync(); }));
if (auto) {
let open = false;
const tick = () => { if (!auto) return; open = !open; item.classList.toggle('is-open', open); sync(); setTimeout(tick, open ? 2000 : 1400); };
setTimeout(tick, 1000);
}
})();
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「小型ドロップダウンナビ」の効果を追加してください。
# 追加してほしい効果
小型ドロップダウンナビ(ヘッダー)
メガメニューほど大きくない、項目ごとの小さなドロップダウン。ホバー/フォーカスで数件のサブリンクをふわっと出します。情報量が中程度のサイトでちょうどよい、扱いやすいナビです。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- 項目ごとの小型ドロップダウンナビ -->
<div class="hdm-frame">
<header class="hdm-head">
<a class="hdm-logo" href="#" onclick="return false">Pine</a>
<nav class="hdm-nav">
<div class="hdm-item" id="hdmItem">
<button class="hdm-trigger" type="button" aria-expanded="false">サービス <span class="hdm-caret">▾</span></button>
<div class="hdm-menu" role="menu">
<a href="#" onclick="return false">サイト制作</a>
<a href="#" onclick="return false">運用・保守</a>
<a href="#" onclick="return false">アクセス解析</a>
</div>
</div>
<a class="hdm-link" href="#" onclick="return false">料金</a>
<a class="hdm-link" href="#" onclick="return false">実績</a>
<a class="hdm-link" href="#" onclick="return false">会社</a>
</nav>
<button class="hdm-cta" type="button">相談する</button>
</header>
<div class="hdm-stage">
<h1>小型ドロップダウン</h1>
<p>「サービス」にホバー/フォーカスで小さな下層メニュー。<br>(自動でも開閉を実演します)</p>
</div>
</div>
【CSS】
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }
.hdm-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #f3f6f4; }
.hdm-head { position: relative; z-index: 5; display: flex; align-items: center; gap: 20px; height: 60px; padding: 0 24px; background: #fff; border-bottom: 1px solid #e4ebe6; }
.hdm-logo { font-size: 19px; font-weight: 800; color: #15803d; text-decoration: none; }
.hdm-nav { display: flex; align-items: center; gap: 4px; }
.hdm-trigger, .hdm-link { font: inherit; font-size: 13.5px; font-weight: 600; color: #2f4137; background: none; border: none; cursor: pointer; text-decoration: none; padding: 8px 12px; border-radius: 8px; display: inline-flex; align-items: center; gap: 5px; transition: background .2s ease, color .2s ease; }
.hdm-trigger:hover, .hdm-link:hover { background: #e7f3eb; color: #15803d; }
.hdm-caret { font-size: 9px; transition: transform .25s ease; }
.hdm-cta { margin-left: auto; font: inherit; font-size: 12.5px; font-weight: 700; color: #fff; background: #15803d; border: none; padding: 9px 17px; border-radius: 999px; cursor: pointer; transition: filter .15s ease, transform .15s ease; }
.hdm-cta:hover { filter: brightness(1.08); transform: translateY(-1px); }
/* 小型ドロップダウン */
.hdm-item { position: relative; }
.hdm-menu {
position: absolute; top: calc(100% + 6px); left: 0; min-width: 168px;
background: #fff; border: 1px solid #e2e8e4; border-radius: 11px; padding: 6px;
box-shadow: 0 16px 34px rgba(20,40,28,.14);
opacity: 0; transform: translateY(-6px); pointer-events: none;
transition: opacity .2s ease, transform .2s ease;
}
.hdm-item:hover .hdm-menu, .hdm-item:focus-within .hdm-menu, .hdm-item.is-open .hdm-menu { opacity: 1; transform: translateY(0); pointer-events: auto; }
.hdm-item:hover .hdm-caret, .hdm-item.is-open .hdm-caret { transform: rotate(180deg); }
.hdm-menu a { display: block; font-size: 13px; color: #2f4137; text-decoration: none; padding: 9px 11px; border-radius: 8px; transition: background .16s ease; }
.hdm-menu a:hover { background: #eef6f0; color: #15803d; }
.hdm-stage { display: grid; place-content: center; height: calc(100% - 60px); text-align: center; color: #243029; padding: 0 24px; }
.hdm-stage h1 { margin: 0; font-size: 26px; font-weight: 800; }
.hdm-stage p { margin: 12px 0 0; font-size: 13px; line-height: 1.8; color: #5d6f63; }
@media (prefers-reduced-motion: reduce) { .hdm-menu, .hdm-caret, .hdm-cta { transition: none; } }
【JavaScript】
// ホバー/フォーカス+自動開閉で小型ドロップダウンを実演
(() => {
const item = document.getElementById('hdmItem');
if (!item) return;
const trigger = item.querySelector('.hdm-trigger');
const sync = () => trigger && trigger.setAttribute('aria-expanded', item.classList.contains('is-open') ? 'true' : 'false');
let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches;
['pointerenter', 'focusin', 'pointerdown'].forEach(ev => item.addEventListener(ev, () => { auto = false; item.classList.remove('is-open'); sync(); }));
if (auto) {
let open = false;
const tick = () => { if (!auto) return; open = !open; item.classList.toggle('is-open', open); sync(); setTimeout(tick, open ? 2000 : 1400); };
setTimeout(tick, 1000);
}
})();
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。