ヘッダー 中級

検索バー展開ヘッダー

虫めがねアイコンをクリックすると、ナビの上をスライドして検索入力欄が伸びてくるヘッダー。普段はすっきり、必要なときだけ検索を前面に出せます。ECやメディアの回遊性を保ちつつ省スペースにできます。

#header#search#expand#navigation

ライブデモ

使用例(お題: SaaS FlowDesk)

この技法を「SaaS FlowDesk」というテーマのダミーサイトで実際に使った例です。

HTML
<!-- FlowDesk:ヘルプセンターの検索展開ヘッダー -->
<div class="hse-frame">
  <header class="hse-head">
    <a class="hse-logo" href="#" onclick="return false">◇ FlowDesk Help</a>
    <nav class="hse-nav">
      <a href="#" onclick="return false">ガイド</a>
      <a href="#" onclick="return false">API</a>
      <a href="#" onclick="return false">よくある質問</a>
    </nav>
    <form class="hse-search" id="hseSearch" onsubmit="return false">
      <input class="hse-input" id="hseInput" type="search" placeholder="ヘルプ記事を検索…" aria-label="検索">
      <button class="hse-btn" id="hseBtn" type="button" aria-label="検索を開く">
        <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21 21l-4.3-4.3M11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
      </button>
    </form>
  </header>
  <div class="hse-stage">
    <h1>お困りですか?</h1>
    <p>右上の検索から、5,000本以上のヘルプ記事を探せます。</p>
  </div>
</div>
CSS
/* FlowDesk(SaaS):検索バー展開ヘッダーの再スキン */
* { box-sizing: border-box; }
body { margin: 0; font-family: "Segoe UI", system-ui, -apple-system, sans-serif; }

.hse-frame { position: relative; width: 100%; height: 380px; overflow: hidden; background: radial-gradient(120% 120% at 50% 0%, #eaeeff, #f6f7fc 60%); }
.hse-head { display: flex; align-items: center; gap: 18px; height: 60px; padding: 0 22px; background: #fff; border-bottom: 1px solid #e7eaf3; }
.hse-logo { font-size: 18px; font-weight: 800; color: #1f2547; text-decoration: none; }
.hse-nav { display: flex; gap: 4px; }
.hse-nav a { color: #3a4060; text-decoration: none; font-size: 13.5px; font-weight: 600; padding: 7px 12px; border-radius: 8px; transition: background .2s ease; }
.hse-nav a:hover { background: #eef1fc; color: #3b5bff; }

.hse-search { display: flex; align-items: center; margin-left: auto; background: #eef1f9; border-radius: 999px; padding: 4px; }
.hse-input { font: inherit; font-size: 13.5px; color: #1f2547; width: 0; opacity: 0; padding: 0; border: none; background: transparent; outline: none; transition: width .35s cubic-bezier(.2,.8,.2,1), opacity .25s ease, padding .35s ease; }
.hse-search.open .hse-input { width: 220px; opacity: 1; padding: 8px 12px; }
.hse-input::placeholder { color: #9aa1b8; }
.hse-btn { flex: 0 0 auto; width: 38px; height: 38px; border: none; cursor: pointer; border-radius: 50%; background: #3b5bff; color: #fff; display: grid; place-items: center; transition: background .2s ease, transform .15s ease; }
.hse-btn svg { width: 18px; height: 18px; }
.hse-btn:hover { background: #2f49d8; transform: scale(1.05); }
.hse-search.open .hse-btn { background: #1f2547; }

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

@media (prefers-reduced-motion: reduce) { .hse-input, .hse-btn { transition: none; } }
JavaScript
// (デモと同じフックを流用)検索アイコンで入力欄を開閉+自動実演
(() => {
  const form = document.getElementById('hseSearch');
  const btn = document.getElementById('hseBtn');
  const input = document.getElementById('hseInput');
  if (!form || !btn) return;
  const set = (open, focus) => {
    form.classList.toggle('open', open);
    btn.setAttribute('aria-label', open ? '検索を閉じる' : '検索を開く');
    if (open && focus && input) try { input.focus(); } catch (e) {}
  };
  let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches;
  btn.addEventListener('click', () => { auto = false; set(!form.classList.contains('open'), true); });
  if (input) input.addEventListener('pointerdown', () => { auto = false; });
  if (auto) {
    let open = false;
    const tick = () => { if (!auto) return; open = !open; set(open); setTimeout(tick, open ? 2400 : 1700); };
    setTimeout(tick, 1100);
  }
})();

実装ガイド

使いどころ

EC・メディア・ヘルプセンターなど検索が主要導線のサイトに。普段はアイコンだけ、必要なときにスライドで検索欄が伸びる省スペース型ヘッダーです。

実装時の注意点

入力欄を width:0→指定幅へトランジションし、opacity と padding も連動させて自然に開きます。開閉は is-open クラスのみで制御。自動デモ時は input.focus() を呼ばず、実クリック時だけフォーカスします(iframe内フォーカスで親がスクロールするのを防ぐため)。

対応ブラウザ

width/opacity のトランジションは全モダンブラウザで安定。type=search の装飾差はブラウザ毎にありますが動作に影響しません。

よくある失敗

幅をピクセル固定にすると狭い画面で溢れるため、max-width や vw も併用を。開いたら自動でフォーカスし、Esc や外側クリックで閉じる導線を用意するとUXが向上。プレースホルダだけで用途が伝わるよう文言を具体的に。

応用例

検索候補(サジェスト)パネルの追加、全画面検索オーバーレイへの拡張、ショートカット(/ キー)でのフォーカス、最近の検索履歴表示などに展開できます。

コード

HTML
<!-- アイコンから検索バーが伸びるヘッダー -->
<div class="hse-frame">
  <header class="hse-head">
    <a class="hse-logo" href="#" onclick="return false">Verge</a>
    <nav class="hse-nav">
      <a href="#" onclick="return false">製品</a>
      <a href="#" onclick="return false">事例</a>
      <a href="#" onclick="return false">料金</a>
      <a href="#" onclick="return false">ブログ</a>
    </nav>
    <form class="hse-search" id="hseSearch" onsubmit="return false">
      <input class="hse-input" id="hseInput" type="search" placeholder="製品・記事を検索…" aria-label="検索">
      <button class="hse-btn" id="hseBtn" type="button" aria-label="検索を開く">
        <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21 21l-4.3-4.3M11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
      </button>
    </form>
  </header>

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

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

.hse-head { display: flex; align-items: center; gap: 18px; height: 60px; padding: 0 22px; background: #fff; border-bottom: 1px solid #e8ebf3; }
.hse-logo { font-size: 19px; font-weight: 800; color: #1f2433; text-decoration: none; letter-spacing: -.01em; }
.hse-nav { display: flex; gap: 4px; }
.hse-nav a { color: #3a4060; text-decoration: none; font-size: 13.5px; font-weight: 600; padding: 7px 12px; border-radius: 8px; transition: background .2s ease; }
.hse-nav a:hover { background: #eef1fb; color: #4f46e5; }

/* 検索:アイコン+伸縮する入力欄 */
.hse-search { display: flex; align-items: center; margin-left: auto; background: #f1f3f9; border-radius: 999px; padding: 4px; }
.hse-input {
  font: inherit; font-size: 13.5px; color: #1f2433;
  width: 0; opacity: 0; padding: 0; border: none; background: transparent; outline: none;
  transition: width .35s cubic-bezier(.2,.8,.2,1), opacity .25s ease, padding .35s ease;
}
.hse-search.open .hse-input { width: 220px; opacity: 1; padding: 8px 12px; }
.hse-input::placeholder { color: #9aa1b1; }
.hse-btn {
  flex: 0 0 auto; width: 38px; height: 38px; border: none; cursor: pointer;
  border-radius: 50%; background: #4f46e5; color: #fff; display: grid; place-items: center;
  transition: background .2s ease, transform .15s ease;
}
.hse-btn svg { width: 18px; height: 18px; }
.hse-btn:hover { background: #4338ca; transform: scale(1.05); }
.hse-search.open .hse-btn { background: #1f2433; }

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

@media (prefers-reduced-motion: reduce) { .hse-input, .hse-btn { transition: none; } }
JavaScript
// 検索アイコンで入力欄を開閉。プレビューでは自動でも実演
(() => {
  const form = document.getElementById('hseSearch');
  const btn = document.getElementById('hseBtn');
  const input = document.getElementById('hseInput');
  if (!form || !btn) return;

  const set = (open, focus) => {
    form.classList.toggle('open', open);
    btn.setAttribute('aria-label', open ? '検索を閉じる' : '検索を開く');
    if (open && focus && input) try { input.focus(); } catch (e) {}
  };

  let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches;
  btn.addEventListener('click', () => { auto = false; set(!form.classList.contains('open'), true); });
  if (input) input.addEventListener('pointerdown', () => { auto = false; });

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

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

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

# 追加してほしい効果
検索バー展開ヘッダー(ヘッダー)
虫めがねアイコンをクリックすると、ナビの上をスライドして検索入力欄が伸びてくるヘッダー。普段はすっきり、必要なときだけ検索を前面に出せます。ECやメディアの回遊性を保ちつつ省スペースにできます。

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

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- アイコンから検索バーが伸びるヘッダー -->
<div class="hse-frame">
  <header class="hse-head">
    <a class="hse-logo" href="#" onclick="return false">Verge</a>
    <nav class="hse-nav">
      <a href="#" onclick="return false">製品</a>
      <a href="#" onclick="return false">事例</a>
      <a href="#" onclick="return false">料金</a>
      <a href="#" onclick="return false">ブログ</a>
    </nav>
    <form class="hse-search" id="hseSearch" onsubmit="return false">
      <input class="hse-input" id="hseInput" type="search" placeholder="製品・記事を検索…" aria-label="検索">
      <button class="hse-btn" id="hseBtn" type="button" aria-label="検索を開く">
        <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M21 21l-4.3-4.3M11 18a7 7 0 1 1 0-14 7 7 0 0 1 0 14Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
      </button>
    </form>
  </header>

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

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

.hse-head { display: flex; align-items: center; gap: 18px; height: 60px; padding: 0 22px; background: #fff; border-bottom: 1px solid #e8ebf3; }
.hse-logo { font-size: 19px; font-weight: 800; color: #1f2433; text-decoration: none; letter-spacing: -.01em; }
.hse-nav { display: flex; gap: 4px; }
.hse-nav a { color: #3a4060; text-decoration: none; font-size: 13.5px; font-weight: 600; padding: 7px 12px; border-radius: 8px; transition: background .2s ease; }
.hse-nav a:hover { background: #eef1fb; color: #4f46e5; }

/* 検索:アイコン+伸縮する入力欄 */
.hse-search { display: flex; align-items: center; margin-left: auto; background: #f1f3f9; border-radius: 999px; padding: 4px; }
.hse-input {
  font: inherit; font-size: 13.5px; color: #1f2433;
  width: 0; opacity: 0; padding: 0; border: none; background: transparent; outline: none;
  transition: width .35s cubic-bezier(.2,.8,.2,1), opacity .25s ease, padding .35s ease;
}
.hse-search.open .hse-input { width: 220px; opacity: 1; padding: 8px 12px; }
.hse-input::placeholder { color: #9aa1b1; }
.hse-btn {
  flex: 0 0 auto; width: 38px; height: 38px; border: none; cursor: pointer;
  border-radius: 50%; background: #4f46e5; color: #fff; display: grid; place-items: center;
  transition: background .2s ease, transform .15s ease;
}
.hse-btn svg { width: 18px; height: 18px; }
.hse-btn:hover { background: #4338ca; transform: scale(1.05); }
.hse-search.open .hse-btn { background: #1f2433; }

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

@media (prefers-reduced-motion: reduce) { .hse-input, .hse-btn { transition: none; } }

【JavaScript】
// 検索アイコンで入力欄を開閉。プレビューでは自動でも実演
(() => {
  const form = document.getElementById('hseSearch');
  const btn = document.getElementById('hseBtn');
  const input = document.getElementById('hseInput');
  if (!form || !btn) return;

  const set = (open, focus) => {
    form.classList.toggle('open', open);
    btn.setAttribute('aria-label', open ? '検索を閉じる' : '検索を開く');
    if (open && focus && input) try { input.focus(); } catch (e) {}
  };

  let auto = !matchMedia('(prefers-reduced-motion: reduce)').matches;
  btn.addEventListener('click', () => { auto = false; set(!form.classList.contains('open'), true); });
  if (input) input.addEventListener('pointerdown', () => { auto = false; });

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

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

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