ダッシュボード · ダッシュボード
数字から読ませるSaaS管理画面
Linear や Vercel の系譜にある、装飾を抑えた実務向けSaaS管理画面の概要ページ。左に件数付きのメニュー、上に指標カード4枚、中央に推移グラフと最近の動き、下に状態を文字でも示す一覧を置き、ログインした人が最初の数秒で状況をつかめる順に並べる。
このブラウザー内に保存します。別の端末との同期はなく、サイトデータを消すと保存も消えます。
印刷時は見本を静止画にし、プロンプトと解説を出力します。PDF保存はブラウザーの印刷画面から選べます。
Vibehaus · デザイン資料
https://vibe.itlibra.com/design/saas-admin-overview/
完全無料・著作権フリー(CC0)· 料金¥0 · 商用利用・改変自由
プレビュー
指定幅で実際に組み替えて表示します。表示領域より広い場合は、この枠の中で横へスクロールできます。
AIへの指示文
請求書クラウドのようなB2B SaaSの管理画面の「概要」ページを作ってください。Linear や Vercel のような、装飾を抑えた実務向けの見た目です。 要件: - 配色: 地 #fafafa、面 #ffffff、サイドバー #f4f4f5、罫線 #e4e4e7、文字 #18181b、補助 #52525b、アクセントは藍 #5b5bd6。影はほぼ使わず罫線で区切る。 - 左に幅232pxのサイドバー。上にワークスペース切替、メニューは「概要/請求書/取引先/入金の照合」と、小見出し付きの「レポート」「ワークスペース」のグループ。各項目の右に件数を薄く出す。選択中は白い面に1pxの枠。 - サイドバーの一番下に、契約プランと利用量のメーター(72 / 100件)。 - 上部は固定のバー。パンくず、⌘K 付きの検索ボタン、アカウントのアイコン。 - ページの見出しの右に、集計期間の切替(7日/30日/90日、aria-pressed で状態を持つ)と主要な操作ボタン1つ。 - 指標カードを4枚横並び。ラベル、大きな数値、前期比、小さな推移線。 - 前期比は「増えたか減ったか」ではなく「良くなったか悪くなったか」で色を決める。未回収が増えたら赤、回収日数が減ったら緑。矢印の向きは増減のまま。 - 中段は2対1の2列。左に請求額と入金額の推移グラフ(入金額は破線にして、色だけに頼らず区別する)、右に最近の動き。 - 下段に直近の請求書の表。金額は右揃え、状態は「✓ 入金済み」「… 支払待ち」「! 期限超過」のように記号と文字を併記したバッジ。 - 数字は font-variant-numeric: tabular-nums で桁を揃える。 - 期間を切り替えたらグラフと見出しの期間表記を描き直す。グラフには role="img" と、期間に合わせて変わる title を付ける。 - 幅1080px未満で指標を2列・中段を1列に、760px未満でサイドバーを隠してボタンで出す。 - フォント: Inter と日本語の system フォント。
バリエーション
ダーク版
地を #0b0b0d、面を #141417、罫線を #26262b、文字を #ededef に。 アクセントは #8b8bf5 に上げ、グラフの塗りは透明度12%にして暗い地で浮かないようにする。
異常を先に出す版
指標カードの上に、対応が必要な項目だけを集めた帯を置く(期限超過3件・照合できない入金1件など)。 帯の各項目は該当する一覧へ絞り込んだ状態で飛ぶリンクにする。
このプレビューのコード
HTML・CSS・JavaScriptの1ファイルです。外部依存・広告・解析コードはありません。架空の請求サービスです。期間別のグラフとスマホメニューを試せます。指標と請求書は固定の見本で、送付・照合・検索・認証・保存・決済は行いません。
コードを表示
<!doctype html>
<!-- Vibehaus · CC0 · 架空のデータを使う1ファイルの表示見本。外部依存・送信・永続保存なし。 -->
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex" />
<title>数字から読ませるSaaS管理画面 — Vibehaus プレビュー</title>
<style>
:root {
--bg: #fafafa;
--panel: #ffffff;
--side: #f4f4f5;
--line: #e4e4e7;
--line-2: #d4d4d8;
--ink: #18181b;
--muted: #52525b;
--quiet: #62626c;
--accent: #5b5bd6;
--accent-soft: #eef0ff;
--up: #15803d;
--down: #b91c1c;
--font: "Inter", system-ui, -apple-system, "Hiragino Sans", "Hiragino Kaku Gothic ProN",
"Yu Gothic Medium", "Yu Gothic", "Meiryo", sans-serif;
--mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, "Meiryo", monospace;
}
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
margin: 0;
font-family: var(--font);
font-size: 14px;
line-height: 1.7;
letter-spacing: 0;
color: var(--ink);
background: var(--bg);
/* 数字の桁を揃える。表とカードの数値が縦に並んだとき比べやすい */
font-variant-numeric: tabular-nums;
}
button { font: inherit; color: inherit; cursor: pointer; }
a { color: inherit; text-decoration: none; }
.app { display: grid; grid-template-columns: 232px minmax(0, 1fr); min-height: 100%; }
/* ---------- サイドバー ---------- */
.side { display: flex; flex-direction: column; gap: 1.2rem; padding: 0.9rem 0.7rem; background: var(--side); border-right: 1px solid var(--line); }
.ws {
display: flex; align-items: center; gap: 0.55rem; width: 100%;
padding: 0.45rem 0.55rem; text-align: left;
background: none; border: 1px solid transparent; border-radius: 8px;
}
.ws:hover { background: #ebebed; }
.ws-mark { display: grid; place-items: center; width: 24px; height: 24px; font-size: 12px; font-weight: 700; color: #fff; background: var(--ink); border-radius: 6px; }
.ws b { font-size: 14px; }
.ws small { margin-left: auto; color: var(--quiet); }
.navgroup p { margin: 0 0 0.25rem 0.55rem; font-size: 12px; font-weight: 600; color: var(--quiet); }
.navgroup ul { margin: 0; padding: 0; list-style: none; }
.navgroup a {
display: flex; align-items: center; gap: 0.55rem;
padding: 0.35rem 0.55rem; color: var(--muted); border-radius: 7px;
}
.navgroup a:hover { color: var(--ink); background: #ebebed; }
.navgroup a[aria-current="location"] { color: var(--ink); font-weight: 600; background: var(--panel); box-shadow: 0 0 0 1px var(--line); }
.ico { width: 16px; text-align: center; color: var(--quiet); }
.count { margin-left: auto; font-size: 12px; color: var(--quiet); }
.plan { margin-top: auto; padding: 0.8rem; font-size: 12px; color: var(--muted); background: var(--panel); border: 1px solid var(--line); border-radius: 10px; }
.plan b { display: block; color: var(--ink); font-size: 13px; }
.meter { height: 5px; margin: 0.5rem 0 0.35rem; overflow: hidden; background: var(--line); border-radius: 99px; }
.meter i { display: block; width: 72%; height: 100%; background: var(--accent); }
/* ---------- 上部 ---------- */
.main { min-width: 0; }
.top {
position: sticky; top: 0; z-index: 5;
display: flex; align-items: center; gap: 0.8rem;
padding: 0.65rem 1.5rem;
background: color-mix(in srgb, var(--bg) 90%, transparent);
backdrop-filter: blur(8px);
border-bottom: 1px solid var(--line);
}
.crumbs { display: flex; gap: 0.4rem; font-size: 13px; color: var(--quiet); }
.crumbs b { color: var(--ink); font-weight: 600; }
.search {
display: flex; align-items: center; gap: 0.5rem; margin-left: auto;
min-width: 240px; padding: 0.35rem 0.6rem;
color: var(--quiet); background: var(--panel);
border: 1px solid var(--line); border-radius: 8px;
}
kbd { margin-left: auto; padding: 0 0.35rem; font-family: var(--mono); font-size: 11px; color: var(--quiet); border: 1px solid var(--line); border-radius: 4px; }
.avatar { width: 28px; height: 28px; display: grid; place-items: center; font-size: 12px; font-weight: 700; color: #fff; background: #e07a5f; border-radius: 50%; }
.menu { display: none; padding: 0.2rem 0.5rem; background: none; border: 1px solid var(--line); border-radius: 6px; }
.page { max-width: 1120px; margin: 0 auto; padding: 1.6rem 1.5rem 3rem; }
.head { display: flex; align-items: flex-end; flex-wrap: wrap; gap: 1rem; margin-bottom: 1.2rem; }
.head h1 { margin: 0; font-size: 22px; line-height: 1.4; }
.head p { margin: 0.15rem 0 0; color: var(--muted); }
.range { display: inline-flex; margin-left: auto; padding: 3px; background: var(--side); border: 1px solid var(--line); border-radius: 9px; }
.range button { padding: 0.25rem 0.75rem; font-size: 13px; color: var(--muted); background: none; border: 0; border-radius: 6px; }
.range button[aria-pressed="true"] { color: var(--ink); font-weight: 600; background: var(--panel); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08); }
.btn { padding: 0.4rem 0.8rem; font-size: 13px; font-weight: 600; color: #fff; background: var(--ink); border: 0; border-radius: 8px; }
/* ---------- 指標 ---------- */
.kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.8rem; margin-bottom: 0.8rem; }
.kpi { padding: 0.9rem 1rem; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; }
.kpi p { margin: 0; font-size: 12px; color: var(--muted); }
.kpi .v { margin: 0.2rem 0 0.1rem; font-size: 24px; font-weight: 700; line-height: 1.35; }
.delta { font-size: 12px; font-weight: 600; }
.delta.up { color: var(--up); }
.delta.down { color: var(--down); }
.delta small { font-weight: 400; color: var(--quiet); }
.spark { display: block; width: 100%; height: 28px; margin-top: 0.4rem; }
/* ---------- グラフと一覧 ---------- */
.grid2 { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 0.8rem; margin-bottom: 0.8rem; }
.card { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; }
.card-h { display: flex; align-items: center; gap: 0.6rem; padding: 0.8rem 1rem; border-bottom: 1px solid var(--line); }
.card-h h2 { margin: 0; font-size: 14px; line-height: 1.4; }
.card-h span { margin-left: auto; font-size: 12px; color: var(--quiet); }
.chart { padding: 0.8rem 1rem 1rem; }
.chart svg { display: block; width: 100%; height: 220px; }
.legend { display: flex; gap: 1rem; margin-top: 0.5rem; font-size: 12px; color: var(--muted); }
.legend i { display: inline-block; width: 10px; height: 3px; margin-right: 0.35rem; vertical-align: middle; border-radius: 2px; }
.feed { margin: 0; padding: 0.4rem 1rem 0.8rem; list-style: none; }
.feed li { display: grid; grid-template-columns: 8px minmax(0, 1fr); gap: 0.7rem; padding: 0.55rem 0; border-bottom: 1px solid var(--line); }
.feed li:last-child { border-bottom: 0; }
.feed .dot { width: 8px; height: 8px; margin-top: 0.5rem; border-radius: 50%; background: var(--accent); }
.feed p { margin: 0; line-height: 1.6; }
.feed small { color: var(--quiet); }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 0.6rem 1rem; text-align: left; border-bottom: 1px solid var(--line); white-space: nowrap; }
th { font-size: 12px; font-weight: 600; color: var(--quiet); background: #fcfcfc; }
td.num, th.num { text-align: right; }
tbody tr:hover { background: #fafafb; }
tbody tr:last-child td { border-bottom: 0; }
.who { display: flex; align-items: center; gap: 0.55rem; }
.who i { display: grid; place-items: center; width: 24px; height: 24px; font-size: 11px; font-style: normal; font-weight: 700; color: var(--accent); background: var(--accent-soft); border-radius: 6px; }
/* 状態は色だけで示さない。文字と記号を必ず併記する */
.badge { display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.05rem 0.5rem; font-size: 12px; font-weight: 600; border-radius: 99px; border: 1px solid; }
.badge.ok { color: var(--up); background: #f0fdf4; border-color: #bbf7d0; }
.badge.wait { color: #a16207; background: #fefce8; border-color: #fde68a; }
.badge.ng { color: var(--down); background: #fef2f2; border-color: #fecaca; }
.tablewrap { overflow-x: auto; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 1080px) {
.kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid2 { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 760px) {
.app { grid-template-columns: minmax(0, 1fr); }
.side { position: fixed; inset: 0 auto 0 0; z-index: 10; width: 240px; transform: translateX(-100%); transition: transform 0.2s; }
.side.open { transform: none; box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.3); }
.menu { display: block; }
.search { min-width: 0; }
.search span { display: none; }
.page { padding: 1.2rem 1rem 2.5rem; }
}
@media (prefers-reduced-motion: reduce) { .side { transition: none; } }
/* 配布見本の操作・説明。配色と主構成は維持する。 */
[hidden]{display:none!important} :focus-visible{outline:3px solid currentColor;outline-offset:3px}
.demo-note{margin:2rem 0 0;padding:1rem;border-top:1px solid currentColor;font:14px/1.8 system-ui,"Hiragino Sans","Meiryo",sans-serif;letter-spacing:0;overflow-wrap:anywhere}
.demo-note h2{font:700 16px/1.5 system-ui,"Hiragino Sans","Meiryo",sans-serif;letter-spacing:0}
.demo-note p{letter-spacing:0;scroll-margin-top:7rem}.demo-note a{display:inline-flex;align-items:center;min-height:44px}
.demo-banner{font:13px/1.7 system-ui,"Hiragino Sans","Meiryo",sans-serif;letter-spacing:0;margin:0 0 1rem}
[data-dashboard-scroll]{max-width:100%;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-gutter:stable}
[data-motion-toggle]{font:inherit;color:inherit;background:transparent;border:1px solid currentColor;border-radius:4px;min-height:44px;padding:.5rem .8rem;margin:0 0 1rem;cursor:pointer;letter-spacing:0}
html:not(.demo-js) *,html[data-motion-paused] *{animation-play-state:paused!important}
html:not(.demo-js) *::before,html:not(.demo-js) *::after,html[data-motion-paused] *::before,html[data-motion-paused] *::after{animation:none!important}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
.app{grid-template-rows:auto 1fr}.main{display:contents}.side{grid-column:1;grid-row:1/span 2;min-width:0}.top{grid-column:2;grid-row:1;flex-wrap:wrap}.page{grid-column:2;grid-row:2;width:100%;min-width:0}.side a,.top a,.range button,.btn,.menu{min-height:44px;display:inline-flex;align-items:center}.side .ws{display:flex}.navgroup a{display:flex}.menu{min-width:44px}.avatar{background:#a8432b}.search{min-width:0}.range button{min-width:44px}.kpi .v{overflow-wrap:anywhere}.card-h{flex-wrap:wrap}.tablewrap table{min-width:660px}.side,.side.open{position:static;inset:auto;transform:none;box-shadow:none;transition:none;width:auto}.crumbs{flex-wrap:wrap}.btn{justify-content:center}.range button:disabled{cursor:default}
@media(max-width:760px){.app{grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto 1fr}.top{grid-column:1;grid-row:1;padding:.65rem 1rem;gap:.5rem}.side{grid-column:1;grid-row:2;border-right:0;border-bottom:1px solid var(--line)}.page{grid-column:1;grid-row:3}.side .navgroup ul{display:flex;flex-wrap:wrap;gap:.4rem}.navgroup a{border:1px solid var(--line)}.plan{margin-top:0}.menu{display:none}.app.is-mobile .menu{display:inline-flex}}@media(max-width:400px){.kpis{grid-template-columns:minmax(0,1fr)}.crumbs{font-size:12px}.avatar{flex-shrink:0}.top .search{margin-left:0}.head .range{margin-left:0}}
.menu{display:none}.app.is-mobile .menu:not([hidden]){display:inline-flex}
</style>
</head>
<body>
<div class="app">
<nav class="side" id="side" aria-label="メインメニュー">
<a class="ws" href="#demo-workspace"><span class="ws-mark">K</span><b>Kakeru 請求</b><small>⌄</small></a>
<div class="navgroup">
<ul>
<li><a href="#demo-overview" aria-current="page"><span class="ico">◧</span>概要</a></li>
<li><a href="#demo-invoices"><span class="ico">▤</span>請求書<span class="count">128</span></a></li>
<li><a href="#demo-customers"><span class="ico">◎</span>取引先<span class="count">46</span></a></li>
<li><a href="#demo-matching"><span class="ico">⇄</span>入金の照合<span class="count">3</span></a></li>
</ul>
</div>
<div class="navgroup">
<p>レポート</p>
<ul>
<li><a href="#demo-sales"><span class="ico">▦</span>売上の推移</a></li>
<li><a href="#demo-unpaid"><span class="ico">◔</span>未回収</a></li>
</ul>
</div>
<div class="navgroup">
<p>ワークスペース</p>
<ul>
<li><a href="#demo-settings"><span class="ico">⚙</span>設定</a></li>
<li><a href="#demo-members"><span class="ico">☺</span>メンバー</a></li>
</ul>
</div>
<div class="plan"><b>スタンダードプラン</b>今月の請求書 72 / 100 件<div class="meter" aria-hidden="true"><i></i></div>更新まで 9日</div>
</nav>
<div class="main">
<header class="top">
<button class="menu" hidden type="button" aria-controls="side" aria-expanded="false">☰<span style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)">メニュー</span></button>
<div class="crumbs"><span>Kakeru 請求</span><span>/</span><b>概要</b></div>
<a class="search" href="#demo-search" aria-label="検索の表示見本について"><span>検索・移動</span><kbd>見本</kbd></a>
<span class="avatar" aria-label="佐藤 さん">佐</span>
</header>
<main class="page"><p class="demo-banner">架空の請求サービスです。期間切替はグラフの固定データだけを変更し、指標・請求書は同じ見本を表示します。</p>
<div class="head">
<div>
<h1>概要</h1>
<p>固定データによる過去30日の表示見本です</p>
</div>
<div class="range" role="group" aria-label="集計期間">
<button type="button" data-range="7" disabled aria-pressed="false">7日</button>
<button type="button" data-range="30" disabled aria-pressed="true">30日</button>
<button type="button" data-range="90" disabled aria-pressed="false">90日</button>
</div>
<a class="btn" href="#demo-create">+ 請求書を作成</a>
</div>
<section class="kpis" aria-label="主要な指標">
<div class="kpi"><p>請求額</p><p class="v" id="k1">¥4,820,400</p><span class="delta up">▲ 12.4% <small>前期比</small></span>
<svg class="spark" viewBox="0 0 100 28" preserveAspectRatio="none" aria-hidden="true"><polyline fill="none" stroke="#5b5bd6" stroke-width="1.6" points="0,22 12,20 24,21 36,16 48,17 60,12 72,13 84,8 100,6"/></svg></div>
<div class="kpi"><p>入金済み</p><p class="v">¥3,912,000</p><span class="delta up">▲ 8.1% <small>前期比</small></span>
<svg class="spark" viewBox="0 0 100 28" preserveAspectRatio="none" aria-hidden="true"><polyline fill="none" stroke="#5b5bd6" stroke-width="1.6" points="0,20 12,21 24,18 36,18 48,14 60,15 72,11 84,12 100,9"/></svg></div>
<div class="kpi"><p>未回収</p><p class="v">¥908,400</p><span class="delta down">▲ 3.2% <small>前期比</small></span>
<svg class="spark" viewBox="0 0 100 28" preserveAspectRatio="none" aria-hidden="true"><polyline fill="none" stroke="#b91c1c" stroke-width="1.6" points="0,18 12,17 24,19 36,15 48,16 60,13 72,14 84,12 100,11"/></svg></div>
<div class="kpi"><p>平均回収日数</p><p class="v">23.6日</p><span class="delta up">▼ 1.8日 <small>前期比</small></span>
<svg class="spark" viewBox="0 0 100 28" preserveAspectRatio="none" aria-hidden="true"><polyline fill="none" stroke="#5b5bd6" stroke-width="1.6" points="0,8 12,9 24,11 36,10 48,14 60,15 72,17 84,18 100,20"/></svg></div>
</section>
<div class="grid2">
<section class="card" aria-labelledby="c-trend">
<div class="card-h"><h2 id="c-trend">請求額と入金額の推移</h2><span id="rangeLabel" aria-live="polite">過去30日</span></div>
<div class="chart">
<svg id="chart" viewBox="0 0 600 220" preserveAspectRatio="none" role="img" aria-labelledby="chart-title">
<title id="chart-title">過去30日の請求額と入金額。どちらも右肩上がりで、差は月末に広がる</title>
<g stroke="#e4e4e7" stroke-width="1">
<line x1="0" y1="40" x2="600" y2="40"/><line x1="0" y1="100" x2="600" y2="100"/><line x1="0" y1="160" x2="600" y2="160"/><line x1="0" y1="219" x2="600" y2="219"/>
</g>
<path id="area" fill="#eef0ff" d="M0.0 149.2 L42.9 141.4 L85.7 143.3 L128.6 129.6 L171.4 121.8 L214.3 125.7 L257.1 110.0 L300.0 100.2 L342.9 104.1 L385.7 90.4 L428.6 78.6 L471.4 70.8 L514.3 74.7 L557.1 59.0 L600.0 43.4 L600 220 L0 220 Z"/>
<path id="lineA" fill="none" stroke="#5b5bd6" stroke-width="2.2" d="M0.0 149.2 L42.9 141.4 L85.7 143.3 L128.6 129.6 L171.4 121.8 L214.3 125.7 L257.1 110.0 L300.0 100.2 L342.9 104.1 L385.7 90.4 L428.6 78.6 L471.4 70.8 L514.3 74.7 L557.1 59.0 L600.0 43.4"/>
<path id="lineB" fill="none" stroke="#a1a1aa" stroke-width="2" stroke-dasharray="5 4" d="M0.0 164.9 L42.9 157.0 L85.7 153.1 L128.6 149.2 L171.4 141.4 L214.3 137.4 L257.1 129.6 L300.0 123.7 L342.9 119.8 L385.7 110.0 L428.6 106.1 L471.4 98.2 L514.3 94.3 L557.1 86.5 L600.0 78.6"/>
</svg>
<div class="legend"><span><i style="background:#5b5bd6"></i>請求額</span><span><i style="background:#a1a1aa"></i>入金額(破線)</span></div>
</div>
</section>
<section class="card" aria-labelledby="c-feed">
<div class="card-h"><h2 id="c-feed">最近の動き</h2><span>すべて見る</span></div>
<ul class="feed">
<li><span class="dot"></span><p>株式会社ミナト から <b>¥320,000</b> の入金を照合しました<br /><small>12分前</small></p></li>
<li><span class="dot" style="background:#a16207"></span><p>請求書 INV-0412 の支払期限が3日後です<br /><small>1時間前</small></p></li>
<li><span class="dot" style="background:#b91c1c"></span><p>入金額が請求額と一致しない取引が <b>1件</b> あります<br /><small>今日 09:12</small></p></li>
<li><span class="dot"></span><p>林 さんが請求書を5件まとめて送付しました<br /><small>昨日</small></p></li>
</ul>
</section>
</div>
<section class="card" aria-labelledby="c-inv">
<div class="card-h"><h2 id="c-inv">直近の請求書</h2><span>128件中 5件</span></div>
<p class="demo-banner" style="padding:.6rem 1rem;margin:0">表は横にスクロールできます。Tabで表に入り、左右キーで移動できます。</p><div class="tablewrap" data-dashboard-scroll tabindex="0" role="region" aria-label="直近の請求書(横スクロール可)">
<table>
<thead><tr><th>取引先</th><th>請求書番号</th><th>期限</th><th>状態</th><th class="num">金額</th></tr></thead>
<tbody>
<tr><td><span class="who"><i>ミ</i>株式会社ミナト</span></td><td>INV-0416</td><td>9月30日</td><td><span class="badge ok">✓ 入金済み</span></td><td class="num">¥320,000</td></tr>
<tr><td><span class="who"><i>ア</i>アオイ設計事務所</span></td><td>INV-0415</td><td>10月5日</td><td><span class="badge wait">… 支払待ち</span></td><td class="num">¥148,500</td></tr>
<tr><td><span class="who"><i>ほ</i>ほしぞら商店</span></td><td>INV-0414</td><td>9月20日</td><td><span class="badge ng">! 期限超過</span></td><td class="num">¥62,700</td></tr>
<tr><td><span class="who"><i>カ</i>カワセミ食品</span></td><td>INV-0413</td><td>10月10日</td><td><span class="badge wait">… 支払待ち</span></td><td class="num">¥1,204,000</td></tr>
<tr><td><span class="who"><i>ニ</i>ニシキ運輸</span></td><td>INV-0412</td><td>9月27日</td><td><span class="badge wait">… 支払待ち</span></td><td class="num">¥87,200</td></tr>
</tbody>
</table>
</div>
</section>
<aside class="demo-note"><h2>この見本について</h2><p>架空のサービス・数値・人物を使った表示見本です。外部通信・永続保存は行いません。配布HTMLはCC0・利用料¥0です。</p><p id="demo-overview" tabindex="-1"><b>概要</b> — 請求サービスの構成を示すページ内の説明です。請求書の送付・入金照合・顧客管理・設定変更は行いません。</p><p id="demo-invoices" tabindex="-1"><b>請求書</b> — 請求サービスの構成を示すページ内の説明です。請求書の送付・入金照合・顧客管理・設定変更は行いません。</p><p id="demo-customers" tabindex="-1"><b>取引先</b> — 請求サービスの構成を示すページ内の説明です。請求書の送付・入金照合・顧客管理・設定変更は行いません。</p><p id="demo-matching" tabindex="-1"><b>入金の照合</b> — 請求サービスの構成を示すページ内の説明です。請求書の送付・入金照合・顧客管理・設定変更は行いません。</p><p id="demo-sales" tabindex="-1"><b>売上の推移</b> — 請求サービスの構成を示すページ内の説明です。請求書の送付・入金照合・顧客管理・設定変更は行いません。</p><p id="demo-unpaid" tabindex="-1"><b>未回収</b> — 請求サービスの構成を示すページ内の説明です。請求書の送付・入金照合・顧客管理・設定変更は行いません。</p><p id="demo-settings" tabindex="-1"><b>設定</b> — 請求サービスの構成を示すページ内の説明です。請求書の送付・入金照合・顧客管理・設定変更は行いません。</p><p id="demo-members" tabindex="-1"><b>メンバー</b> — 請求サービスの構成を示すページ内の説明です。請求書の送付・入金照合・顧客管理・設定変更は行いません。</p><p id="demo-workspace" tabindex="-1"><b>ワークスペース</b> — 切替・契約・認証は未実装です。</p><p id="demo-search" tabindex="-1"><b>検索</b> — 検索欄の配置を示す見本です。検索とショートカットは未実装です。</p><p id="demo-create" tabindex="-1"><b>請求書の作成</b> — ボタンの配置を示す見本です。請求書の作成・保存・送信・決済は行いません。</p></aside></main>
</div>
</div>
<script>
// 集計期間に応じてグラフを描き直す。値は見本用の固定データ
const SERIES = {
7: { a: [62, 70, 66, 78, 84, 80, 92], b: [50, 58, 60, 64, 70, 72, 76], label: "過去7日" },
30: { a: [30, 34, 33, 40, 44, 42, 50, 55, 53, 60, 66, 70, 68, 76, 84], b: [22, 26, 28, 30, 34, 36, 40, 43, 45, 50, 52, 56, 58, 62, 66], label: "過去30日" },
90: { a: [20, 26, 24, 30, 36, 34, 42, 40, 48, 54, 52, 60, 66, 72, 80], b: [16, 20, 22, 24, 28, 30, 32, 36, 38, 42, 46, 48, 52, 58, 62], label: "過去90日" },
};
const W = 600, H = 220, PAD = 12;
const toPts = (arr) => arr.map((v, i) => [(i / (arr.length - 1)) * W, H - PAD - (v / 100) * (H - PAD * 2)]);
const pathOf = (pts) => pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
function draw(range) {
const s = SERIES[range];
const a = toPts(s.a), b = toPts(s.b);
document.getElementById("lineA").setAttribute("d", pathOf(a));
document.getElementById("lineB").setAttribute("d", pathOf(b));
document.getElementById("area").setAttribute("d", pathOf(a) + ` L${W} ${H} L0 ${H} Z`);
document.getElementById("rangeLabel").textContent = s.label;
document.getElementById("chart-title").textContent = `${s.label}の請求額と入金額。どちらも右肩上がり`;
}
document.querySelector(".range").addEventListener("click", (e) => {
const btn = e.target.closest("button[data-range]");
if (!btn) return;
document.querySelectorAll(".range button").forEach((b) => b.setAttribute("aria-pressed", String(b === btn)));
draw(btn.dataset.range);
document.querySelector(".head>div>p").textContent = "固定データによる" + SERIES[btn.dataset.range].label + "の表示見本です";
});
draw(30);
document.querySelectorAll('.range button').forEach(button=>button.disabled=false);
document.querySelector('.head>div>p').textContent='固定データによる過去30日の表示見本です';
const side = document.getElementById("side");
const menu = document.querySelector(".menu");
const app=document.querySelector('.app'),mobile=matchMedia('(max-width:760px)');
function setOpen(open,restore=false){if(!open&&restore)menu.focus();side.hidden=mobile.matches&&!open;menu.setAttribute('aria-expanded',String(open));}
function syncMenu(){const focus=document.activeElement;if(mobile.matches){app.classList.add('is-mobile');if(side.contains(focus))menu.focus()}else{side.hidden=false;if(focus===menu)side.querySelector('a').focus();app.classList.remove('is-mobile')}setOpen(false);}
menu.hidden=false;menu.addEventListener('click',()=>{const open=menu.getAttribute('aria-expanded')!=='true';setOpen(open);if(open)side.querySelector('a').focus()});
document.addEventListener('keydown',e=>{if(e.key==='Escape'&&mobile.matches&&!side.hidden){e.preventDefault();setOpen(false,true)}});
document.addEventListener('pointerdown',e=>{if(mobile.matches&&!side.hidden&&!side.contains(e.target)&&!menu.contains(e.target))setOpen(false,side.contains(document.activeElement))});
document.addEventListener('focusin',e=>{if(mobile.matches&&!side.hidden&&!side.contains(e.target)&&e.target!==menu)setOpen(false)});
side.addEventListener('click',e=>{if(e.target.closest('a')&&mobile.matches)setOpen(false,true)});
mobile.addEventListener('change',syncMenu);syncMenu();
function syncCurrent(){const target=location.hash||'#demo-overview';document.querySelectorAll('.navgroup a').forEach(a=>{if(a.hash===target)a.setAttribute('aria-current','location');else a.removeAttribute('aria-current')})}
addEventListener('hashchange',syncCurrent);syncCurrent();
</script>
</body>
</html>
2026年10月14日、Chromiumで320・390・768・1280pxの描画とキーボードのフォーカス表示を確認しました。他のブラウザは未確認です。利用先のブラウザと実データでも確認してください。
概要
B2B SaaSの管理画面は、2020年代に入って見た目の方向が1つにまとまりました。Linear、Vercel、Stripe の管理画面に代表される、白い面と1pxの罫線、控えめな1色のアクセント、影をほとんど使わない組み方です。派手さを捨てたのは、この画面が毎日開かれる仕事の道具だからです。
開いて最初の数秒で何が分かるか
概要ページの仕事は、ログインした人に「いま何か問題が起きていないか」を数秒で伝えることです。そのために、上から下へ情報の粒度を細かくしていきます。
崩れる形グラフを最上段に大きく置く
見栄えは良くなりますが、読み取りに時間がかかります。いくらなのかという答えが、線の傾きを見て推測するものになってしまいます。
効く形数字、推移、明細の順に置く
最上段で数字を答え、中段で流れを見せ、下段で個別の明細へ降ります。知りたいことの粒度の順に並べると、多くの人は上の数行だけで用が済みます。
色は増減ではなく良し悪しに付ける
前期比の色でよくある失敗が、「増えたら緑、減ったら赤」で統一してしまうことです。未回収の金額やエラーの件数は、増えるほど悪い数字です。回収にかかる日数は、減るほど良い数字です。
矢印の向きは増減、色は良くなったか悪くなったか。役割を分けておけば、減ってほしい指標の良い知らせが警告に見えることはありません。
仕上げの判断軸
状態のバッジは、色だけで示さず記号と文字を併記します。緑と赤の区別が付きにくい人は珍しくありません。グラフの2本の線も同じで、片方を破線にして色以外でも見分けられるようにします。
装飾を抑えた画面は、細部の粗が目立ちます。サイドバーの件数、表の金額の右揃え、罫線の太さを揃えるといった小さな一貫性が、そのまま製品への信頼になります。
ダッシュボードの構成要素
使いどころ
- 請求・会計・在庫などB2B SaaSのログイン直後の画面
- 社内向け管理ツールのトップページ
- 事業の数字を毎朝確認する経営者向けの画面
- SaaSのLPに載せる製品画面のモック
このデザインの分類
背景と狙いどころ
よくある質問
指標カードは何枚が適切?
前期比が下がって緑になるのは分かりにくくない?
グラフは何のライブラリで描くべき?
この画面を実装する
動くサンプルとコピペできるコードを、技術別にまとめています。
関連するデザイン
アイソメトリック倉庫の在庫ダッシュボード
倉庫のラックを45度の立体で並べ、高さで在庫量、色で充填率を同時に読ませる管理画面。表とグラフでは伝わらない「どこが詰まっているか」を一目で示します。
サイバー調のダッシュボード画面
黒背景にネオンの発光色、モノスペースフォントを組み合わせたサイバーパンク調の管理画面。KPI・ライブチャート・ログテーブル・リージョン別レイテンシを 1 画面にまとめた、開発者向けSaaSの観測系ダッシュボード。
空港パタパタ式発車案内板風のダッシュボード
空港・駅の split-flap(パタパタ式)発車案内板を再構築したオペレーションダッシュボード。タイル状の数字ボード・色分けステータス・LIVE 表示で「業務の流れが見える」OPS 体験を作る尖った設計。