Flexbox ホーリーグレイル
ヘッダー・フッターと固定幅の両サイド+伸縮する中央カラムを Flexbox で構成する定番の3カラム管理画面レイアウト。
ライブデモ
使用例(お題: 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で提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。