Flexbox ホーリーグレイル

ヘッダー・フッターと固定幅の両サイド+伸縮する中央カラムを Flexbox で構成する定番の3カラム管理画面レイアウト。

#css#flexbox#layout

ライブデモ

使用例(お題: SaaS FlowDesk)

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

HTML
<!-- FlowDesk 管理画面:Flexbox ホーリーグレイルで3カラム構成 -->
<div class="fd-app">
  <header class="fd-app__header">
    <span class="fd-app__logo">◆ FlowDesk</span>
    <nav class="fd-app__topnav">
      <a class="is-active">ダッシュボード</a>
      <a>レポート</a>
      <a>設定</a>
    </nav>
    <span class="fd-app__user">田中 ◉</span>
  </header>

  <div class="fd-app__body">
    <!-- 固定幅サイドナビ -->
    <aside class="fd-app__nav">
      <p class="fd-app__nav-h">MENU</p>
      <a class="is-active">📊 概況</a>
      <a>👥 メンバー</a>
      <a>📁 プロジェクト</a>
      <a>💳 請求</a>
    </aside>

    <!-- 伸縮する中央カラム -->
    <main class="fd-app__main">
      <h1 class="fd-app__title">今週の概況</h1>
      <div class="fd-app__kpis">
        <div class="fd-kpi"><span>稼働タスク</span><b>128</b><i class="up">+12%</i></div>
        <div class="fd-kpi"><span>完了率</span><b>87%</b><i class="up">+4%</i></div>
        <div class="fd-kpi"><span>遅延</span><b>3</b><i class="down">-2</i></div>
      </div>
      <div class="fd-app__panel">
        <p class="fd-app__panel-h">アクティビティ</p>
        <ul class="fd-app__feed">
          <li><span class="dot dot--b"></span>佐藤さんが「請求API」を完了</li>
          <li><span class="dot dot--b"></span>新規プロジェクト「Q3刷新」を作成</li>
          <li><span class="dot"></span>山田さんがコメントを追加</li>
        </ul>
      </div>
    </main>

    <!-- 固定幅サイドパネル -->
    <aside class="fd-app__side">
      <p class="fd-app__nav-h">期限が近い</p>
      <div class="fd-app__task"><b>UIレビュー</b><span>明日 17:00</span></div>
      <div class="fd-app__task"><b>請求書送付</b><span>6/9</span></div>
      <button class="fd-app__cta" type="button">+ タスク追加</button>
    </aside>
  </div>

  <footer class="fd-app__footer">© 2026 FlowDesk Inc. ・ すべての権限</footer>
</div>
CSS
/* FlowDesk:Flexbox ホーリーグレイル(ヘッダー/フッター+固定両サイド+伸縮中央) */
:root {
  --navy: #0f1b34;
  --blue: #4f7cff;
  --ink: #1b2742;
  --line: #e4e9f5;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  height: 400px;
  font-family: "Hiragino Kaku Gothic ProN", "Segoe UI", system-ui, sans-serif;
  background: #eef2fb;
  color: var(--ink);
  overflow: hidden;
}

/* 縦方向の Flex:ヘッダー / 本体 / フッター */
.fd-app {
  height: 400px;
  display: flex;
  flex-direction: column;
  background: #f6f8fe;
}

.fd-app__header {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 16px;
  height: 46px;
  background: var(--navy);
  color: #fff;
  flex: 0 0 auto;
}
.fd-app__logo { font-weight: 800; letter-spacing: 0.04em; font-size: 14px; }
.fd-app__topnav { display: flex; gap: 16px; font-size: 12px; }
.fd-app__topnav a { color: #aebbd8; cursor: pointer; }
.fd-app__topnav a.is-active { color: #fff; }
.fd-app__user { margin-left: auto; font-size: 12px; color: #cdd7ef; }

/* 横方向の Flex:左ナビ / 中央 / 右パネル */
.fd-app__body {
  flex: 1;
  display: flex;
  min-height: 0;
}

/* 固定幅サイド */
.fd-app__nav {
  flex: 0 0 132px;
  background: #fff;
  border-right: 1px solid var(--line);
  padding: 14px 10px;
}
.fd-app__side {
  flex: 0 0 160px;
  background: #fff;
  border-left: 1px solid var(--line);
  padding: 14px 12px;
}
.fd-app__nav-h {
  margin: 0 0 8px;
  font-size: 9px;
  letter-spacing: 0.18em;
  color: #8a97b8;
  font-weight: 700;
}
.fd-app__nav a {
  display: block;
  font-size: 12px;
  padding: 7px 8px;
  border-radius: 7px;
  color: #4a5a7e;
  cursor: pointer;
}
.fd-app__nav a.is-active { background: #eef3ff; color: var(--blue); font-weight: 700; }

/* 伸縮する中央カラム */
.fd-app__main {
  flex: 1;
  min-width: 0;
  padding: 14px 16px;
  overflow: auto;
}
.fd-app__title { margin: 0 0 12px; font-size: 16px; font-weight: 800; }

.fd-app__kpis { display: flex; gap: 10px; margin-bottom: 12px; }
.fd-kpi {
  flex: 1;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px 12px;
}
.fd-kpi span { font-size: 10px; color: #7e8cae; }
.fd-kpi b { display: block; font-size: 20px; margin: 2px 0; }
.fd-kpi i { font-size: 10px; font-style: normal; font-weight: 700; }
.fd-kpi i.up { color: #1f9d63; }
.fd-kpi i.down { color: #d8584f; }

.fd-app__panel {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px 14px;
}
.fd-app__panel-h { margin: 0 0 8px; font-size: 12px; font-weight: 700; }
.fd-app__feed { list-style: none; margin: 0; padding: 0; }
.fd-app__feed li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  padding: 5px 0;
  color: #46557a;
}
.dot { width: 7px; height: 7px; border-radius: 50%; background: #c4cde4; flex: 0 0 auto; }
.dot--b { background: var(--blue); }

.fd-app__task {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: 11px;
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
}
.fd-app__task b { font-weight: 700; }
.fd-app__task span { color: #8a97b8; }
.fd-app__cta {
  margin-top: 12px;
  width: 100%;
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  background: var(--blue);
  border: none;
  padding: 9px 0;
  border-radius: 8px;
  cursor: pointer;
}
.fd-app__cta:hover { background: #3f6cf0; }

.fd-app__footer {
  flex: 0 0 auto;
  height: 30px;
  display: flex;
  align-items: center;
  padding: 0 16px;
  font-size: 10px;
  color: #8a97b8;
  background: #fff;
  border-top: 1px solid var(--line);
}
JavaScript
// サイドナビ&トップナビのアクティブ切替(管理画面らしい操作感)
function wireNav(selector) {
  const links = document.querySelectorAll(selector);
  links.forEach((link) => {
    link.addEventListener("click", () => {
      links.forEach((l) => l.classList.remove("is-active"));
      link.classList.add("is-active");
    });
  });
}

wireNav(".fd-app__nav a");
wireNav(".fd-app__topnav a");

// タスク追加ボタンで件数フィードバック
const cta = document.querySelector(".fd-app__cta");
cta?.addEventListener("click", () => {
  cta.textContent = "✓ 追加しました";
  setTimeout(() => { cta.textContent = "+ タスク追加"; }, 1300);
});

コード

HTML
<!-- Flexbox ホーリーグレイル:ヘッダー/フッターと3カラム本体を flex で構成 -->
<div class="hg">
  <header class="hg__header">
    <span class="hg__brand">◆ HolyGrail</span>
    <nav class="hg__nav">
      <a href="#" data-nav>Home</a>
      <a href="#" data-nav>Docs</a>
      <a href="#" data-nav>About</a>
    </nav>
  </header>

  <div class="hg__body">
    <aside class="hg__side hg__side--left">
      <p class="hg__label">NAV</p>
      <ul>
        <li>Dashboard</li>
        <li>Projects</li>
        <li>Team</li>
        <li>Settings</li>
      </ul>
    </aside>

    <main class="hg__main">
      <p class="hg__label">MAIN</p>
      <h1>伸縮する3カラム</h1>
      <p class="hg__text">
        両サイドは固定幅、中央は flex:1 で残り幅を吸収。
        ヘッダーとフッターを除いた高さいっぱいに本体が広がります。
      </p>
      <div class="hg__chips">
        <span>flex-grow</span><span>flex-shrink</span><span>order</span>
      </div>
    </main>

    <aside class="hg__side hg__side--right">
      <p class="hg__label">ASIDE</p>
      <div class="hg__card">Tip 01</div>
      <div class="hg__card">Tip 02</div>
    </aside>
  </div>

  <footer class="hg__footer">© 2026 — Flexbox Layout Pattern</footer>
</div>
CSS
/* 全体:濃紺ベースのダッシュボード風 */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: "Hiragino Sans", system-ui, sans-serif;
  background: linear-gradient(160deg, #0f172a, #1e293b);
  color: #e2e8f0;
  display: grid; place-items: center;
  min-height: 100vh; padding: 14px;
}

/* 縦方向の flex:header / body / footer */
.hg {
  width: min(900px, 100%);
  height: min(330px, 90vh);
  display: flex; flex-direction: column;
  border-radius: 14px; overflow: hidden;
  background: #0b1220;
  border: 1px solid #243049;
  box-shadow: 0 20px 50px -24px rgba(0,0,0,.7);
}

/* ヘッダー */
.hg__header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 18px; background: #111c33; border-bottom: 1px solid #243049;
}
.hg__brand { font-weight: 800; letter-spacing: .06em; color: #7dd3fc; }
.hg__nav { display: flex; gap: 6px; }
.hg__nav a {
  color: #cbd5e1; text-decoration: none; font-size: 13px;
  padding: 6px 12px; border-radius: 8px; transition: background .2s, color .2s;
}
.hg__nav a:hover, .hg__nav a.is-active { background: #1d2c49; color: #7dd3fc; }

/* 本体:横方向の flex で3カラム */
.hg__body { display: flex; flex: 1; min-height: 0; }

.hg__side {
  flex: 0 0 140px; padding: 14px;
  display: flex; flex-direction: column; gap: 10px;
  background: #0e1830;
}
.hg__side--right { flex-basis: 130px; }

/* 中央カラムが残り幅を占有 */
.hg__main {
  flex: 1; padding: 18px 20px; min-width: 0;
  display: flex; flex-direction: column; gap: 10px;
  background:
    radial-gradient(100% 120% at 100% 0%, rgba(56,189,248,.12), transparent 60%);
}
.hg__label {
  font-size: 10px; letter-spacing: .28em; color: #64748b; font-weight: 700;
}
.hg__main h1 { font-size: clamp(20px, 3.4vw, 28px); color: #f1f5f9; }
.hg__text { font-size: 13px; line-height: 1.7; color: #b6c2d4; max-width: 46ch; }

.hg__side ul { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.hg__side li {
  font-size: 13px; color: #cbd5e1; padding: 7px 10px; border-radius: 8px;
  background: #15233f; transition: transform .2s, background .2s; cursor: default;
}
.hg__side li:hover { background: #1d2c49; transform: translateX(3px); }

.hg__card {
  font-size: 13px; padding: 12px; border-radius: 10px; color: #0b1220;
  background: linear-gradient(135deg, #7dd3fc, #38bdf8); font-weight: 700;
}

.hg__chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.hg__chips span {
  font-size: 11px; padding: 4px 10px; border-radius: 20px;
  background: #1d2c49; color: #7dd3fc; border: 1px solid #2b3d61;
}

/* フッター */
.hg__footer {
  padding: 10px 18px; background: #111c33; border-top: 1px solid #243049;
  font-size: 12px; color: #8295ad; text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .hg__side li, .hg__nav a { transition: none; }
}
JavaScript
// ナビのアクティブ表示をクリックで切り替え(null安全)
(() => {
  const links = document.querySelectorAll('[data-nav]');
  if (!links.length) return;
  links[0].classList.add('is-active'); // 初期アクティブ
  links.forEach((link) => {
    link.addEventListener('click', (e) => {
      e.preventDefault();
      links.forEach((l) => l.classList.remove('is-active'));
      link.classList.add('is-active');
    });
  });
})();

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

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

# 追加してほしい効果
Flexbox ホーリーグレイル(レイアウト & グリッド)
ヘッダー・フッターと固定幅の両サイド+伸縮する中央カラムを Flexbox で構成する定番の3カラム管理画面レイアウト。

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

# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- Flexbox ホーリーグレイル:ヘッダー/フッターと3カラム本体を flex で構成 -->
<div class="hg">
  <header class="hg__header">
    <span class="hg__brand">◆ HolyGrail</span>
    <nav class="hg__nav">
      <a href="#" data-nav>Home</a>
      <a href="#" data-nav>Docs</a>
      <a href="#" data-nav>About</a>
    </nav>
  </header>

  <div class="hg__body">
    <aside class="hg__side hg__side--left">
      <p class="hg__label">NAV</p>
      <ul>
        <li>Dashboard</li>
        <li>Projects</li>
        <li>Team</li>
        <li>Settings</li>
      </ul>
    </aside>

    <main class="hg__main">
      <p class="hg__label">MAIN</p>
      <h1>伸縮する3カラム</h1>
      <p class="hg__text">
        両サイドは固定幅、中央は flex:1 で残り幅を吸収。
        ヘッダーとフッターを除いた高さいっぱいに本体が広がります。
      </p>
      <div class="hg__chips">
        <span>flex-grow</span><span>flex-shrink</span><span>order</span>
      </div>
    </main>

    <aside class="hg__side hg__side--right">
      <p class="hg__label">ASIDE</p>
      <div class="hg__card">Tip 01</div>
      <div class="hg__card">Tip 02</div>
    </aside>
  </div>

  <footer class="hg__footer">© 2026 — Flexbox Layout Pattern</footer>
</div>

【CSS】
/* 全体:濃紺ベースのダッシュボード風 */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
  font-family: "Hiragino Sans", system-ui, sans-serif;
  background: linear-gradient(160deg, #0f172a, #1e293b);
  color: #e2e8f0;
  display: grid; place-items: center;
  min-height: 100vh; padding: 14px;
}

/* 縦方向の flex:header / body / footer */
.hg {
  width: min(900px, 100%);
  height: min(330px, 90vh);
  display: flex; flex-direction: column;
  border-radius: 14px; overflow: hidden;
  background: #0b1220;
  border: 1px solid #243049;
  box-shadow: 0 20px 50px -24px rgba(0,0,0,.7);
}

/* ヘッダー */
.hg__header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 18px; background: #111c33; border-bottom: 1px solid #243049;
}
.hg__brand { font-weight: 800; letter-spacing: .06em; color: #7dd3fc; }
.hg__nav { display: flex; gap: 6px; }
.hg__nav a {
  color: #cbd5e1; text-decoration: none; font-size: 13px;
  padding: 6px 12px; border-radius: 8px; transition: background .2s, color .2s;
}
.hg__nav a:hover, .hg__nav a.is-active { background: #1d2c49; color: #7dd3fc; }

/* 本体:横方向の flex で3カラム */
.hg__body { display: flex; flex: 1; min-height: 0; }

.hg__side {
  flex: 0 0 140px; padding: 14px;
  display: flex; flex-direction: column; gap: 10px;
  background: #0e1830;
}
.hg__side--right { flex-basis: 130px; }

/* 中央カラムが残り幅を占有 */
.hg__main {
  flex: 1; padding: 18px 20px; min-width: 0;
  display: flex; flex-direction: column; gap: 10px;
  background:
    radial-gradient(100% 120% at 100% 0%, rgba(56,189,248,.12), transparent 60%);
}
.hg__label {
  font-size: 10px; letter-spacing: .28em; color: #64748b; font-weight: 700;
}
.hg__main h1 { font-size: clamp(20px, 3.4vw, 28px); color: #f1f5f9; }
.hg__text { font-size: 13px; line-height: 1.7; color: #b6c2d4; max-width: 46ch; }

.hg__side ul { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.hg__side li {
  font-size: 13px; color: #cbd5e1; padding: 7px 10px; border-radius: 8px;
  background: #15233f; transition: transform .2s, background .2s; cursor: default;
}
.hg__side li:hover { background: #1d2c49; transform: translateX(3px); }

.hg__card {
  font-size: 13px; padding: 12px; border-radius: 10px; color: #0b1220;
  background: linear-gradient(135deg, #7dd3fc, #38bdf8); font-weight: 700;
}

.hg__chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.hg__chips span {
  font-size: 11px; padding: 4px 10px; border-radius: 20px;
  background: #1d2c49; color: #7dd3fc; border: 1px solid #2b3d61;
}

/* フッター */
.hg__footer {
  padding: 10px 18px; background: #111c33; border-top: 1px solid #243049;
  font-size: 12px; color: #8295ad; text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .hg__side li, .hg__nav a { transition: none; }
}

【JavaScript】
// ナビのアクティブ表示をクリックで切り替え(null安全)
(() => {
  const links = document.querySelectorAll('[data-nav]');
  if (!links.length) return;
  links[0].classList.add('is-active'); // 初期アクティブ
  links.forEach((link) => {
    link.addEventListener('click', (e) => {
      e.preventDefault();
      links.forEach((l) => l.classList.remove('is-active'));
      link.classList.add('is-active');
    });
  });
})();

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

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