ヘッダー 中級

サイドバー・ドロワーナビ

ハンバーガーで左から滑り込むドロワー型サイドナビ。背景は暗幕で覆い、項目は時間差で現れます。階層の深いサイトや管理画面、モバイル導線に向く定番のスライドメニューです。

#header#drawer#sidebar#navigation

ライブデモ

使用例(お題: アイドルグループ Sakura)

この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。

HTML
<!-- Sakura:公式サイトのドロワーナビ -->
<div class="hsd-frame" id="hsdFrame">
  <header class="hsd-head">
    <button class="hsd-burger" id="hsdBurger" type="button" aria-label="メニュー" aria-expanded="false">
      <span></span><span></span><span></span>
    </button>
    <a class="hsd-logo" href="#" onclick="return false">✿ SAKURA</a>
    <button class="hsd-cta" type="button">ファンクラブ</button>
  </header>

  <div class="hsd-overlay" id="hsdOverlay" aria-hidden="true"></div>
  <aside class="hsd-drawer" id="hsdDrawer" aria-hidden="true">
    <p class="hsd-drawer__h">メニュー</p>
    <nav class="hsd-list">
      <a style="--i:0" href="#" onclick="return false">ニュース</a>
      <a style="--i:1" href="#" onclick="return false">ライブ・イベント</a>
      <a style="--i:2" href="#" onclick="return false">メンバー</a>
      <a style="--i:3" href="#" onclick="return false">ディスコグラフィ</a>
      <a style="--i:4" href="#" onclick="return false">グッズ</a>
    </nav>
  </aside>

  <div class="hsd-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; }

.hsd-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #fff0f6; }
.hsd-head { position: relative; z-index: 5; display: flex; align-items: center; gap: 14px; height: 58px; padding: 0 18px; background: #fff; border-bottom: 1px solid #ffd9e8; }
.hsd-burger { width: 38px; height: 38px; position: relative; background: none; border: none; cursor: pointer; padding: 0; }
.hsd-burger span { position: absolute; left: 8px; right: 8px; height: 2px; background: #6a2447; border-radius: 2px; transition: transform .3s ease, opacity .2s ease; }
.hsd-burger span:nth-child(1) { top: 13px; }
.hsd-burger span:nth-child(2) { top: 18px; }
.hsd-burger span:nth-child(3) { top: 23px; }
.hsd-frame.is-open .hsd-burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.hsd-frame.is-open .hsd-burger span:nth-child(2) { opacity: 0; }
.hsd-frame.is-open .hsd-burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
.hsd-logo { font-size: 18px; font-weight: 800; color: #d6336c; text-decoration: none; letter-spacing: .04em; }
.hsd-cta { margin-left: auto; font: inherit; font-size: 12.5px; font-weight: 700; color: #d6336c; background: #ffe3ee; border: none; padding: 8px 15px; border-radius: 999px; cursor: pointer; }

.hsd-overlay { position: absolute; inset: 0; z-index: 8; background: rgba(40,15,28,.45); opacity: 0; pointer-events: none; transition: opacity .35s ease; }
.hsd-frame.is-open .hsd-overlay { opacity: 1; pointer-events: auto; }

.hsd-drawer { position: absolute; top: 0; bottom: 0; left: 0; z-index: 9; width: 240px; background: #fff; box-shadow: 8px 0 30px rgba(120,30,70,.18); padding: 22px 18px; transform: translateX(-100%); transition: transform .38s cubic-bezier(.2,.8,.2,1); }
.hsd-frame.is-open .hsd-drawer { transform: translateX(0); }
.hsd-drawer__h { margin: 0 0 14px; font-size: 11px; letter-spacing: .12em; font-weight: 700; color: #c98aa8; text-transform: uppercase; }
.hsd-list { display: flex; flex-direction: column; gap: 2px; }
.hsd-list a { color: #5a2440; text-decoration: none; font-size: 14px; font-weight: 600; padding: 11px 12px; border-radius: 10px; opacity: 0; transform: translateX(-12px); transition: background .2s ease, opacity .3s ease, transform .3s ease; }
.hsd-list a:hover { background: #fff0f6; color: #d6336c; }
.hsd-frame.is-open .hsd-list a { opacity: 1; transform: translateX(0); transition-delay: calc(.12s + var(--i) * 55ms); }

.hsd-stage { display: grid; place-content: center; height: calc(100% - 58px); text-align: center; color: #6a2447; padding: 0 24px; }
.hsd-stage h1 { margin: 0; font-size: 26px; font-weight: 800; }
.hsd-stage p { margin: 12px 0 0; font-size: 13px; line-height: 1.8; color: #a8718c; }

@media (prefers-reduced-motion: reduce) { .hsd-overlay, .hsd-drawer, .hsd-list a, .hsd-burger span { transition: none; } }
JavaScript
// (デモと同じフックを流用)ドロワーの開閉+自動実演
(() => {
  const frame = document.getElementById('hsdFrame');
  const burger = document.getElementById('hsdBurger');
  const overlay = document.getElementById('hsdOverlay');
  const drawer = document.getElementById('hsdDrawer');
  if (!frame || !burger) return;
  const set = (open) => {
    frame.classList.toggle('is-open', open);
    burger.setAttribute('aria-expanded', open ? 'true' : 'false');
    if (overlay) overlay.setAttribute('aria-hidden', open ? 'false' : 'true');
    if (drawer) drawer.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 (overlay) overlay.addEventListener('click', () => { auto = false; set(false); });
  if (auto) {
    let open = false;
    const tick = () => { if (!auto) return; open = !open; set(open); setTimeout(tick, open ? 2600 : 1700); };
    setTimeout(tick, 1100);
  }
})();

実装ガイド

使いどころ

階層の深いサイト・管理画面・モバイル導線に。ハンバーガーで左から滑り込むドロワー型サイドナビで、項目を時間差で見せて没入感を出します。

実装時の注意点

ドロワーは translateX(-100%)→0、暗幕はフェードで連動。項目は --i を使った transition-delay で順に現れます。is-open をフレームに付けるだけで全要素が動きます。暗幕クリックでも閉じます。

対応ブラウザ

transform・opacity・transition は全モダンブラウザ対応。clip や filter を使わないため軽量です。

よくある失敗

開いている間は背面スクロールを止める(body overflow:hidden)配慮が実サイトでは必要。フォーカストラップと Esc 閉じでアクセシビリティを担保。右からのドロワーにする場合は translateX の符号と影の向きを反転します。

応用例

右側ドロワー、多階層メニュー(アコーディオン入れ子)、ドロワー内に検索やアカウント情報を載せる、スワイプジェスチャ対応などに展開できます。

コード

HTML
<!-- ハンバーガー → 左から滑り込むドロワーナビ -->
<div class="hsd-frame" id="hsdFrame">
  <header class="hsd-head">
    <button class="hsd-burger" id="hsdBurger" type="button" aria-label="メニュー" aria-expanded="false">
      <span></span><span></span><span></span>
    </button>
    <a class="hsd-logo" href="#" onclick="return false">◐ Atlas</a>
    <button class="hsd-cta" type="button">ログイン</button>
  </header>

  <div class="hsd-overlay" id="hsdOverlay" aria-hidden="true"></div>
  <aside class="hsd-drawer" id="hsdDrawer" aria-hidden="true">
    <p class="hsd-drawer__h">メニュー</p>
    <nav class="hsd-list">
      <a style="--i:0" href="#" onclick="return false">ダッシュボード</a>
      <a style="--i:1" href="#" onclick="return false">プロジェクト</a>
      <a style="--i:2" href="#" onclick="return false">メンバー</a>
      <a style="--i:3" href="#" onclick="return false">レポート</a>
      <a style="--i:4" href="#" onclick="return false">設定</a>
    </nav>
  </aside>

  <div class="hsd-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; }

.hsd-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #eef1f7; }

.hsd-head { position: relative; z-index: 5; display: flex; align-items: center; gap: 14px; height: 58px; padding: 0 18px; background: #fff; border-bottom: 1px solid #e6e9f2; }
.hsd-burger { width: 38px; height: 38px; position: relative; background: none; border: none; cursor: pointer; padding: 0; }
.hsd-burger span { position: absolute; left: 8px; right: 8px; height: 2px; background: #2a3050; border-radius: 2px; transition: transform .3s ease, opacity .2s ease; }
.hsd-burger span:nth-child(1) { top: 13px; }
.hsd-burger span:nth-child(2) { top: 18px; }
.hsd-burger span:nth-child(3) { top: 23px; }
.hsd-frame.is-open .hsd-burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.hsd-frame.is-open .hsd-burger span:nth-child(2) { opacity: 0; }
.hsd-frame.is-open .hsd-burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
.hsd-logo { font-size: 18px; font-weight: 800; color: #4f46e5; text-decoration: none; }
.hsd-cta { margin-left: auto; font: inherit; font-size: 12.5px; font-weight: 700; color: #4f46e5; background: #eef0fe; border: none; padding: 8px 15px; border-radius: 999px; cursor: pointer; }

/* 暗幕 */
.hsd-overlay { position: absolute; inset: 0; z-index: 8; background: rgba(15,18,40,.45); opacity: 0; pointer-events: none; transition: opacity .35s ease; }
.hsd-frame.is-open .hsd-overlay { opacity: 1; pointer-events: auto; }

/* ドロワー */
.hsd-drawer {
  position: absolute; top: 0; bottom: 0; left: 0; z-index: 9; width: 240px;
  background: #fff; box-shadow: 8px 0 30px rgba(20,24,50,.18);
  padding: 22px 18px; transform: translateX(-100%); transition: transform .38s cubic-bezier(.2,.8,.2,1);
}
.hsd-frame.is-open .hsd-drawer { transform: translateX(0); }
.hsd-drawer__h { margin: 0 0 14px; font-size: 11px; letter-spacing: .12em; font-weight: 700; color: #9aa1b8; text-transform: uppercase; }
.hsd-list { display: flex; flex-direction: column; gap: 2px; }
.hsd-list a {
  color: #2a3050; text-decoration: none; font-size: 14px; font-weight: 600;
  padding: 11px 12px; border-radius: 10px;
  opacity: 0; transform: translateX(-12px);
  transition: background .2s ease, opacity .3s ease, transform .3s ease;
  transition-delay: 0s;
}
.hsd-list a:hover { background: #f1f3fb; color: #4f46e5; }
.hsd-frame.is-open .hsd-list a { opacity: 1; transform: translateX(0); transition-delay: calc(.12s + var(--i) * 55ms); }

.hsd-stage { display: grid; place-content: center; height: calc(100% - 58px); text-align: center; color: #2a3050; padding: 0 24px; }
.hsd-stage h1 { margin: 0; font-size: 26px; font-weight: 800; }
.hsd-stage p { margin: 12px 0 0; font-size: 13px; line-height: 1.8; color: #6a7090; }

@media (prefers-reduced-motion: reduce) { .hsd-overlay, .hsd-drawer, .hsd-list a, .hsd-burger span { transition: none; } }
JavaScript
// ドロワーの開閉。プレビューでは自動でも開閉を実演
(() => {
  const frame = document.getElementById('hsdFrame');
  const burger = document.getElementById('hsdBurger');
  const overlay = document.getElementById('hsdOverlay');
  const drawer = document.getElementById('hsdDrawer');
  if (!frame || !burger) return;

  const set = (open) => {
    frame.classList.toggle('is-open', open);
    burger.setAttribute('aria-expanded', open ? 'true' : 'false');
    if (overlay) overlay.setAttribute('aria-hidden', open ? 'false' : 'true');
    if (drawer) drawer.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 (overlay) overlay.addEventListener('click', () => { auto = false; set(false); });

  if (auto) {
    let open = false;
    const tick = () => { if (!auto) return; open = !open; set(open); setTimeout(tick, open ? 2600 : 1700); };
    setTimeout(tick, 1100);
  }
})();

🤖 AIエージェント用プロンプト

このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「サイドバー・ドロワーナビ」の効果を追加してください。

# 追加してほしい効果
サイドバー・ドロワーナビ(ヘッダー)
ハンバーガーで左から滑り込むドロワー型サイドナビ。背景は暗幕で覆い、項目は時間差で現れます。階層の深いサイトや管理画面、モバイル導線に向く定番のスライドメニューです。

# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- ハンバーガー → 左から滑り込むドロワーナビ -->
<div class="hsd-frame" id="hsdFrame">
  <header class="hsd-head">
    <button class="hsd-burger" id="hsdBurger" type="button" aria-label="メニュー" aria-expanded="false">
      <span></span><span></span><span></span>
    </button>
    <a class="hsd-logo" href="#" onclick="return false">◐ Atlas</a>
    <button class="hsd-cta" type="button">ログイン</button>
  </header>

  <div class="hsd-overlay" id="hsdOverlay" aria-hidden="true"></div>
  <aside class="hsd-drawer" id="hsdDrawer" aria-hidden="true">
    <p class="hsd-drawer__h">メニュー</p>
    <nav class="hsd-list">
      <a style="--i:0" href="#" onclick="return false">ダッシュボード</a>
      <a style="--i:1" href="#" onclick="return false">プロジェクト</a>
      <a style="--i:2" href="#" onclick="return false">メンバー</a>
      <a style="--i:3" href="#" onclick="return false">レポート</a>
      <a style="--i:4" href="#" onclick="return false">設定</a>
    </nav>
  </aside>

  <div class="hsd-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; }

.hsd-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: #eef1f7; }

.hsd-head { position: relative; z-index: 5; display: flex; align-items: center; gap: 14px; height: 58px; padding: 0 18px; background: #fff; border-bottom: 1px solid #e6e9f2; }
.hsd-burger { width: 38px; height: 38px; position: relative; background: none; border: none; cursor: pointer; padding: 0; }
.hsd-burger span { position: absolute; left: 8px; right: 8px; height: 2px; background: #2a3050; border-radius: 2px; transition: transform .3s ease, opacity .2s ease; }
.hsd-burger span:nth-child(1) { top: 13px; }
.hsd-burger span:nth-child(2) { top: 18px; }
.hsd-burger span:nth-child(3) { top: 23px; }
.hsd-frame.is-open .hsd-burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.hsd-frame.is-open .hsd-burger span:nth-child(2) { opacity: 0; }
.hsd-frame.is-open .hsd-burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
.hsd-logo { font-size: 18px; font-weight: 800; color: #4f46e5; text-decoration: none; }
.hsd-cta { margin-left: auto; font: inherit; font-size: 12.5px; font-weight: 700; color: #4f46e5; background: #eef0fe; border: none; padding: 8px 15px; border-radius: 999px; cursor: pointer; }

/* 暗幕 */
.hsd-overlay { position: absolute; inset: 0; z-index: 8; background: rgba(15,18,40,.45); opacity: 0; pointer-events: none; transition: opacity .35s ease; }
.hsd-frame.is-open .hsd-overlay { opacity: 1; pointer-events: auto; }

/* ドロワー */
.hsd-drawer {
  position: absolute; top: 0; bottom: 0; left: 0; z-index: 9; width: 240px;
  background: #fff; box-shadow: 8px 0 30px rgba(20,24,50,.18);
  padding: 22px 18px; transform: translateX(-100%); transition: transform .38s cubic-bezier(.2,.8,.2,1);
}
.hsd-frame.is-open .hsd-drawer { transform: translateX(0); }
.hsd-drawer__h { margin: 0 0 14px; font-size: 11px; letter-spacing: .12em; font-weight: 700; color: #9aa1b8; text-transform: uppercase; }
.hsd-list { display: flex; flex-direction: column; gap: 2px; }
.hsd-list a {
  color: #2a3050; text-decoration: none; font-size: 14px; font-weight: 600;
  padding: 11px 12px; border-radius: 10px;
  opacity: 0; transform: translateX(-12px);
  transition: background .2s ease, opacity .3s ease, transform .3s ease;
  transition-delay: 0s;
}
.hsd-list a:hover { background: #f1f3fb; color: #4f46e5; }
.hsd-frame.is-open .hsd-list a { opacity: 1; transform: translateX(0); transition-delay: calc(.12s + var(--i) * 55ms); }

.hsd-stage { display: grid; place-content: center; height: calc(100% - 58px); text-align: center; color: #2a3050; padding: 0 24px; }
.hsd-stage h1 { margin: 0; font-size: 26px; font-weight: 800; }
.hsd-stage p { margin: 12px 0 0; font-size: 13px; line-height: 1.8; color: #6a7090; }

@media (prefers-reduced-motion: reduce) { .hsd-overlay, .hsd-drawer, .hsd-list a, .hsd-burger span { transition: none; } }

【JavaScript】
// ドロワーの開閉。プレビューでは自動でも開閉を実演
(() => {
  const frame = document.getElementById('hsdFrame');
  const burger = document.getElementById('hsdBurger');
  const overlay = document.getElementById('hsdOverlay');
  const drawer = document.getElementById('hsdDrawer');
  if (!frame || !burger) return;

  const set = (open) => {
    frame.classList.toggle('is-open', open);
    burger.setAttribute('aria-expanded', open ? 'true' : 'false');
    if (overlay) overlay.setAttribute('aria-hidden', open ? 'false' : 'true');
    if (drawer) drawer.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 (overlay) overlay.addEventListener('click', () => { auto = false; set(false); });

  if (auto) {
    let open = false;
    const tick = () => { if (!auto) return; open = !open; set(open); setTimeout(tick, open ? 2600 : 1700); };
    setTimeout(tick, 1100);
  }
})();

# 外部ライブラリ
なし(追加ライブラリ不要)

# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。