空状態 · 空状態
幾何形を組み替える空状態
赤い円・青い四角・黄色い三角の5つの図形だけで空の画面を成立させる空状態。ボタンを押すと同じ図形が配置を変え、待つ時間に小さな手触りを与えます。
このブラウザー内に保存します。別の端末との同期はなく、サイトデータを消すと保存も消えます。
印刷時は見本を静止画にし、プロンプトと解説を出力します。PDF保存はブラウザーの印刷画面から選べます。
Vibehaus · デザイン資料
https://vibe.itlibra.com/design/bauhaus-empty-state/
完全無料・著作権フリー(CC0)· 料金¥0 · 商用利用・改変自由
プレビュー
指定幅で実際に組み替えて表示します。表示領域より広い場合は、この枠の中で横へスクロールできます。
AIへの指示文
業務ツールの空状態(データがまだ1件もない画面)を、バウハウス様式の幾何構成で作ってください。 要件: - 配色: 生成りの紙 #f4f1ea、黒 #171717、赤 #e2482f、青 #2b4a9b、黄 #f4c430。中間色は使わない。 - 左に正方形の作図枠を置き、3×3の薄い罫線を敷く。その上に5つの図形だけを配置する: 青い四角、赤い円、黄色い三角、黒い横棒、黄色いリング。 - 右に見出し・説明・行動ボタン。見出しの一部を黄色のマーカーで塗る。 - 「構成を組み替える」ボタンを置き、押すと5つの図形が transform で別の配置へ動く。図形は増減させない。 - 動きは cubic-bezier(0.34, 1.3, 0.64, 1) で軽く跳ねさせ、prefers-reduced-motion では無効にする。 - ボタンは矩形(角丸なし)、3pxの黒ボーダー、押すと2px沈む。主ボタンは黒地・紙色文字。 - 最下部に赤・黄・青・黒の色帯を敷く。 - 見出しは「まだ、何も置かれていません」のように、失敗ではなく状態として書く。 - 日本語は letter-spacing 0、見出しの行間1.35、本文1.85。
バリエーション
検索結果ゼロ版
見出しを「その条件に合うものはありません」に変え、 図形の配置を「探しても見つからない」ように散らす。絞り込み解除ボタンを主導線にする。
エラー復帰版
赤い円を大きくして中央に置き、他の図形を周縁に追いやる。 再試行ボタンとステータスページへのリンクを並べる。
このプレビューのコード
HTML・CSS・JavaScriptの1ファイルです。外部依存・広告・解析コードはありません。固定のプロジェクト1件の追加と初期化、3つのタブ、5図形の組み替えを試せる見本です。実際の作成・招待・取り込み・外部送信・永続保存は行いません。動きの停止とOSの動き低減に対応します。
コードを表示
<!doctype html>
<!-- Vibehaus · CC0 · 架空の制作管理の見本。外部依存・作成・送信・永続保存なし。 -->
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex" />
<title>幾何形を組み替える空状態 — Vibehaus プレビュー</title>
<style>
:root {
--paper: #f4f1ea;
--ink: #171717;
--red: #e2482f;
--blue: #2b4a9b;
--yellow: #f4c430;
--dim: #6a655e;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
min-height: 100vh;
font-family: "Helvetica Neue", "Inter", "Hiragino Kaku Gothic ProN",
"Noto Sans JP", "Yu Gothic", "Meiryo", sans-serif;
background: var(--paper);
color: var(--ink);
line-height: 1.8;
-webkit-font-smoothing: antialiased;
}
header.bar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0.9rem clamp(1rem, 4vw, 2.5rem);
border-bottom: 3px solid var(--ink);
}
.brand {
display: inline-flex;
align-items: center;
gap: 0.55rem;
font-weight: 800;
font-size: 0.98rem;
line-height: 1.5;
}
.brand i {
width: 16px; height: 16px;
background: var(--red);
display: inline-block;
}
.tabs {
display: flex;
gap: 0;
font-size: 0.8rem;
line-height: 1.6;
font-weight: 700;
}
.tabs span {
padding: 0.3rem 0.85rem;
border: 2px solid var(--ink);
border-right-width: 0;
}
.tabs span:last-child { border-right-width: 2px; }
.tabs .on { background: var(--yellow); }
@media (max-width: 620px) { .tabs { display: none; } }
main {
max-width: 940px;
margin: 0 auto;
padding: clamp(2rem, 6vw, 4.5rem) clamp(1rem, 4vw, 2.5rem) 2rem;
display: grid;
grid-template-columns: 300px 1fr;
gap: clamp(1.5rem, 5vw, 3.5rem);
align-items: center;
}
@media (max-width: 780px) {
main { grid-template-columns: 1fr; }
}
/* --- The composition: five primitives on a 3x3 bed ----------------- */
.composition {
position: relative;
width: 100%;
aspect-ratio: 1;
border: 3px solid var(--ink);
background:
linear-gradient(var(--ink) 1px, transparent 1px) 0 0 / 100% 33.333%,
linear-gradient(90deg, var(--ink) 1px, transparent 1px) 0 0 / 33.333% 100%,
var(--paper);
}
.composition > * {
position: absolute;
transition: transform 0.45s cubic-bezier(0.34, 1.3, 0.64, 1),
border-radius 0.45s ease, background 0.45s ease;
}
.sq {
left: 6%; top: 6%;
width: 40%; height: 40%;
background: var(--blue);
}
.ci {
right: 8%; top: 10%;
width: 30%; height: 30%;
background: var(--red);
border-radius: 50%;
}
.tri {
left: 12%; bottom: 8%;
width: 0; height: 0;
border-left: 52px solid transparent;
border-right: 52px solid transparent;
border-bottom: 88px solid var(--yellow);
}
.bar-h {
right: 6%; bottom: 22%;
width: 34%; height: 14px;
background: var(--ink);
}
.ring {
left: 44%; top: 46%;
width: 22%; aspect-ratio: 1;
border: 12px solid var(--yellow);
border-radius: 50%;
background: transparent;
}
/* Rearranged state — the same five parts, a different sentence. */
.composition.alt .sq { transform: translate(58%, 118%) rotate(45deg); }
.composition.alt .ci { transform: translate(-30%, 96%); background: var(--blue); }
.composition.alt .tri { transform: translate(150%, -150%) rotate(180deg); }
.composition.alt .bar-h { transform: translate(-40%, -280%) rotate(90deg); }
.composition.alt .ring { transform: translate(-90%, -30%) scale(0.72); border-color: var(--red); }
@media (prefers-reduced-motion: reduce) {
.composition > * { transition: none; }
}
.copy .num {
font-family: "JetBrains Mono", ui-monospace, monospace;
font-size: 0.72rem;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--dim);
margin: 0 0 0.9rem;
}
h1 {
margin: 0 0 1rem;
font-size: clamp(1.85rem, 5vw, 3rem);
line-height: 1.35;
font-weight: 900;
}
h1 em {
font-style: normal;
background: var(--yellow);
padding: 0 0.15em;
}
.copy p {
margin: 0 0 1.75rem;
max-width: 42ch;
font-size: 1rem;
line-height: 1.85;
color: var(--dim);
}
.actions { display: flex; gap: 0; flex-wrap: wrap; }
.btn {
font: inherit;
font-size: 0.92rem;
line-height: 1.6;
font-weight: 800;
padding: 0.8rem 1.5rem;
border: 3px solid var(--ink);
cursor: pointer;
text-decoration: none;
color: var(--ink);
background: var(--paper);
transition: background 0.15s, color 0.15s, transform 0.08s;
}
.btn.primary { background: var(--ink); color: var(--paper); border-right-width: 0; }
.btn.primary:hover { background: var(--red); border-color: var(--red); }
.btn.ghost:hover { background: var(--yellow); }
.btn:active { transform: translateY(2px); }
@media (max-width: 460px) {
.btn { width: 100%; border-right-width: 3px; }
.btn.primary { border-bottom-width: 0; }
}
.hint {
margin: 1.75rem 0 0;
padding-top: 1rem;
border-top: 2px solid var(--ink);
font-size: 0.84rem;
line-height: 1.8;
color: var(--dim);
max-width: 42ch;
}
.hint b { color: var(--ink); }
footer.strip { display: flex; height: 12px; }
footer.strip > * { flex: 1; }
footer.strip .a { background: var(--red); }
footer.strip .b { background: var(--yellow); }
footer.strip .c { background: var(--blue); }
footer.strip .d { background: var(--ink); }
[hidden]{display:none!important}button,input{font-family:inherit}button:disabled{cursor:default;opacity:.65}:focus-visible{outline:3px solid currentColor;outline-offset:3px}
button,a,summary{min-height:44px;min-width:44px}button{cursor:pointer}a,section{scroll-margin-top:1rem}.demo-caption,.demo-status{font-size:13px;line-height:1.8;letter-spacing:0;overflow-wrap:anywhere}.demo-status{border-left:3px solid currentColor;padding-left:.75rem}
.demo-note{font-size:13px;line-height:1.8;letter-spacing:0;margin-top:2rem;border-top:1px solid currentColor;padding-top:1rem;overflow-wrap:anywhere}.demo-note h2{font-size:18px;line-height:1.5;letter-spacing:0}.demo-note h3{font-size:15px;line-height:1.5;letter-spacing:0}.demo-note a{display:inline-flex;align-items:center;min-height:44px}.demo-note p{letter-spacing:0}.demo-tabs{flex-wrap:wrap;gap:.35rem}.demo-tabs button{font:inherit;letter-spacing:0;min-height:44px;min-width:44px}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
header.bar{flex-wrap:wrap}.tabs{display:flex!important}.tabs button{background:var(--paper);color:var(--ink);border:2px solid var(--ink);padding:.4rem .65rem}.tabs [aria-selected="true"]{background:var(--yellow)}main{grid-template-columns:300px minmax(0,1fr)}.composition{max-width:300px;justify-self:center}.tri{width:35%;height:30%;border:0;background:var(--yellow);clip-path:polygon(50% 0,100% 100%,0 100%)}.composition.alt .sq{transform:translate(45%,85%) rotate(45deg) scale(.85)}.composition.alt .ci{transform:translate(-85%,120%)}.composition.alt .tri{transform:translate(120%,-140%) rotate(180deg)}
.actions{gap:.5rem}.btn.primary{border-right-width:3px}.btn.primary:hover{background:#ad3020;border-color:#ad3020}.btn{max-width:100%;overflow-wrap:anywhere}.hint a{display:inline-flex;align-items:center;color:var(--blue);min-height:44px}.motion-controls{margin-top:.75rem}.motion-toggle{font:inherit;font-size:13px;background:transparent;color:var(--ink);border:1px solid var(--ink);padding:.4rem .6rem}.project-card{margin-top:1rem;border:3px solid var(--ink);padding:1rem}.project-card h2{font-size:20px;line-height:1.5;margin:0 0 .5rem}.project-card p{font-size:14px;margin-bottom:1rem}.note-wrap{max-width:940px;margin:auto;padding:0 clamp(1rem,4vw,2.5rem) 2rem}.demo-status:focus,.project-card:focus{outline:3px solid var(--ink);outline-offset:4px}.copy .demo-status{font-size:13px;margin-top:1rem;color:var(--ink)}html[data-motion-paused] .composition>*{transition:none!important}.copy{min-width:0}
@media(max-width:780px){main{grid-template-columns:1fr;padding-top:2rem}}@media(max-width:460px){.btn.primary{border-bottom-width:3px}}
.copy h1{text-wrap:balance;overflow-wrap:anywhere}.note-wrap .demo-note{margin-top:0}
</style>
</head>
<body>
<header class="bar">
<div class="brand"><i aria-hidden="true"></i>GRID — 制作管理</div>
<div class="tabs demo-tabs" role="tablist" aria-label="制作管理の表示見本"><button class="tab" type="button" id="tab-0" role="tab" aria-selected="true" aria-controls="panel-0" tabindex="0" data-js-control disabled>プロジェクト</button><button class="tab" type="button" id="tab-1" role="tab" aria-selected="false" aria-controls="panel-1" tabindex="-1" data-js-control disabled>メンバー</button><button class="tab" type="button" id="tab-2" role="tab" aria-selected="false" aria-controls="panel-2" tabindex="-1" data-js-control disabled>アーカイブ</button></div>
</header>
<main>
<div class="composition" id="comp" aria-hidden="true">
<span class="sq"></span>
<span class="ci"></span>
<span class="tri"></span>
<span class="bar-h"></span>
<span class="ring"></span>
</div>
<div class="copy"><section id="panel-0" role="tabpanel" aria-labelledby="tab-0" tabindex="0"><p class="num" data-project-count>Demo · 000 projects</p><h1 id="project-heading">まだ、<em>何も置かれていません</em></h1><p id="project-description">最初の1件を並べるための画面です。ボタンから固定の見本を追加できます。実際のプロジェクト作成・保存は行いません。</p><div class="actions"><button class="btn primary" type="button" data-project-create data-js-control disabled>最初のプロジェクトを作る(見本)</button><button class="btn ghost" type="button" id="shuffle" aria-pressed="false" data-js-control disabled>構成を組み替える</button></div><div class="motion-controls"><button type="button" class="motion-toggle" data-motion-toggle aria-pressed="false" data-js-control disabled>動きを止める</button></div><p class="demo-status" data-project-status role="status" hidden></p><section class="project-card" data-project-card tabindex="-1" aria-labelledby="demo-project-title" hidden><h2 id="demo-project-title">はじめてのプロジェクト</h2><p>固定の1件をページ内に表示しています。作成・同期・外部送信・永続保存はしていません。</p><button class="btn ghost" type="button" data-project-reset>空の見本に戻す</button></section><p class="hint"><b>ヒント</b>/<a href="#demo-template">テンプレート</a>と<a href="#demo-import">取り込み</a>の見本も確認できます。</p></section><section id="panel-1" role="tabpanel" aria-labelledby="tab-1" tabindex="0" hidden><p class="num">Demo · members</p><h1>メンバー表示の見本</h1><p>メンバーや権限を案内する画面の見本です。招待メールの送信・権限変更・登録は行いません。</p><button class="btn ghost" type="button" data-project-tab>プロジェクトの見本へ戻る</button></section><section id="panel-2" role="tabpanel" aria-labelledby="tab-2" tabindex="0" hidden><p class="num">Demo · archive</p><h1>アーカイブ表示の見本</h1><p>保管したプロジェクトを案内する画面の見本です。実データの保管・移動・削除は行いません。</p><button class="btn ghost" type="button" data-project-tab>プロジェクトの見本へ戻る</button></section></div></main><div class="note-wrap"><aside class="demo-note"><h2>この見本について</h2><p>架空の制作管理画面です。タブの表示切替、ページ内の見本1件の追加と初期化、5つの図形の組み替えを試せます。外部サービスへの接続・実データの作成・保存はなく、再読み込みで初期状態に戻ります。配布HTMLはCC0・利用料¥0です。</p><section id="demo-template" tabindex="-1"><h3>テンプレートの見本</h3><p>空の画面から近道を示すリンク位置の例です。テンプレートの適用や設定画面は実装していません。</p></section><section id="demo-import" tabindex="-1"><h3>取り込みの見本</h3><p>既存データへの入口を示すリンク位置の例です。ファイル・リポジトリの読込や外部接続は行いません。</p></section><noscript><p>JavaScriptが無効なためタブとボタンの操作はできません。初期画面と説明リンクを表示します。</p></noscript></aside></div>
<footer class="strip" aria-hidden="true">
<span class="a"></span><span class="b"></span><span class="c"></span><span class="d"></span>
</footer>
<script>
const tabs=[...document.querySelectorAll('[role="tab"]')];
function selectTab(index,focus=false){tabs.forEach((tab,i)=>{const selected=i===index;tab.setAttribute('aria-selected',String(selected));tab.tabIndex=selected?0:-1;tab.classList.toggle('on',selected);tab.classList.toggle('active',selected)});updatePanel(index);if(focus)tabs[index].focus()}
tabs.forEach((tab,index)=>{tab.addEventListener('click',()=>selectTab(index));tab.addEventListener('keydown',event=>{let next;if(event.key==='ArrowRight')next=(index+1)%tabs.length;else if(event.key==='ArrowLeft')next=(index+tabs.length-1)%tabs.length;else if(event.key==='Home')next=0;else if(event.key==='End')next=tabs.length-1;else return;event.preventDefault();selectTab(next,true)})});
function updatePanel(index){document.querySelectorAll('[role="tabpanel"]').forEach((panel,i)=>panel.hidden=i!==index)}
document.querySelectorAll('[data-project-tab]').forEach(button=>button.addEventListener('click',()=>selectTab(0,true)));
const comp=document.getElementById('comp'),shuffle=document.getElementById('shuffle'),create=document.querySelector('[data-project-create]'),card=document.querySelector('[data-project-card]'),status=document.querySelector('[data-project-status]'),heading=document.querySelector('#project-heading'),description=document.querySelector('#project-description'),count=document.querySelector('[data-project-count]');
shuffle.addEventListener('click',()=>{const alt=comp.classList.toggle('alt');shuffle.setAttribute('aria-pressed',String(alt));shuffle.textContent=alt?'元の構成に戻す':'構成を組み替える'});
create.addEventListener('click',()=>{card.hidden=false;create.disabled=true;count.textContent='Demo · 001 project';heading.firstChild.textContent='最初の';heading.querySelector('em').textContent='1件が並びました';description.textContent='固定の見本を1件表示しました。別のタブから戻っても表示を保ち、空の見本へ戻すか再読み込みすると初期状態に戻ります。';status.hidden=false;status.textContent='ページ内で見本を1件表示しました。実データの作成・送信・保存はしていません。';card.focus()});
document.querySelector('[data-project-reset]').addEventListener('click',()=>{card.hidden=true;create.disabled=false;count.textContent='Demo · 000 projects';heading.firstChild.textContent='まだ、';heading.querySelector('em').textContent='何も置かれていません';description.textContent='最初の1件を並べるための画面です。ボタンから固定の見本を追加できます。実際のプロジェクト作成・保存は行いません。';status.hidden=true;status.textContent='';create.focus()});
const toggle=document.querySelector('[data-motion-toggle]'),motion=matchMedia('(prefers-reduced-motion: reduce)');let paused=false;
function syncMotion(){const stopped=paused||motion.matches;document.documentElement.toggleAttribute('data-motion-paused',stopped);toggle.setAttribute('aria-pressed',String(stopped));toggle.disabled=motion.matches;toggle.textContent=motion.matches?'動きを減らす設定で停止中':stopped?'動きを再開':'動きを止める'}
toggle.addEventListener('click',()=>{paused=!paused;syncMotion()});motion.addEventListener('change',syncMotion);
document.querySelectorAll('[data-js-control]').forEach(el=>el.disabled=false);selectTab(0);syncMotion();
</script>
</body>
</html>
2026年10月14日、Chromiumで320・390・768・1280pxの描画とキーボードのフォーカス表示を確認しました。他のブラウザは未確認です。利用先のブラウザと実データでも確認してください。
概要
バウハウスの基礎課程では、ヨハネス・イッテンやヨゼフ・アルバースが、限られた材料をどう組み替えるかを学生に課しました。素材を増やさず、配置だけで意味を変える——この訓練の思想は、要素が何もない画面をどう見せるかという問題と、そのまま重なります。
空は失敗ではない
初回ログイン直後、リストは必ず空です。にもかかわらず多くのプロダクトはこの画面を後回しにし、灰色の「データがありません」を置いて済ませます。ユーザーから見れば、それは壊れた画面と区別がつきません。空状態は、サービスとの関係が始まる最初の1画面であり、最初の1件を作らせるための専用ページです。だから見出しは「まだ、何も置かれていません」——欠落ではなく、これから何を並べるかを決められる状態として書きます。
5つの図形だけで成立させる
青い四角、赤い円、黄色い三角、黒い棒、黄色いリング。この5つを3×3の罫線の上に置くだけで画面は成立します。イラストレーターに発注する必要も、空箱や虫眼鏡のありふれたアイコンを使う必要もありません。「構成を組み替える」ボタンを押すと、同じ5つが位置と角度を変えて別の配置になります。図形は1つも増減しない——これはバウハウスの課題そのものであり、待たされている数秒に小さな手触りを与える仕掛けでもあります。主導線はあくまで「最初のプロジェクトを作る」で、遊びは常に副次に置きます。
見本で試せる範囲
「最初のプロジェクトを作る(見本)」を押すと、固定の1件がページ内に並びます。メンバー・アーカイブのタブへ移動して戻っても見本は残り、「空の見本に戻す」か再読み込みで初期状態へ戻ります。タブは左右キー・Home・Endでも選べます。テンプレートと取り込みは説明へのリンクです。実際の作成・招待・取り込み・外部送信・永続保存は行いません。
図形の組み替えは途中も枠内に収まり、同じ5つを往復させます。「動きを止める」かOSの動き低減が有効なら、配置だけを即座に切り替えます。配布HTMLは外部素材を取得せず、保存した1ファイルだけで動きます。
仕上げの判断軸
原色と太い黒罫は業務ツールの他画面から浮きやすいので、空状態だけに使うのか、プロダクト全体の言語にするのかを先に決めてください。中途半端に一画面だけ様式が変わると、統一感の欠如として読まれます。動きは prefers-reduced-motion で必ず止め、ヒント文には最初の1件を作る具体的な近道——テンプレート、既存データの取り込み——を1行で添えます。
空状態の成功は美しさでは測りません。次の画面へ進んだ人の割合で測ります。
空状態の構成要素
使いどころ
- 業務ツールの初回ログイン直後
- プロジェクト・タスクが0件のリスト
- アップロード前のメディア管理画面
- デザイン色の強いBtoBプロダクト
- チュートリアルへの導線を置きたい場面
このデザインの分類
背景と狙いどころ
よくある質問
空状態に凝る意味はありますか?
図形が動く仕掛けは邪魔では?
イラストを描く余力がない場合は?
「まだありません」以外に書くことは?
この画面を実装する
動くサンプルとコピペできるコードを、技術別にまとめています。
関連するデザイン
親しみのあるイラスト付き空状態(受信箱が空)
受信箱や通知センターが空のときの画面UI。シンプルなイラスト・1 行のコピー・1 つの明確なCTAで、「何もない」状態を「次のアクションへ」変える設計。
バウハウス様式・幾何構成の原色ヒーロー
1919年バウハウス・ロシア構成主義を引用した、原色×幾何形×グロテスクサンセリフのヒーロー。20世紀モダンデザインの古典をWebに再構築する、教養と前衛が同居する尖った設計。
ストリートグラフィティ風の404ページ
コンクリート壁にスプレー塗料で殴り書きされた「404」を主役にしたストリートグラフィティ風 404 ページ。剥がれかけのポスター、タグ、スプラッタ、警告テープ。失敗ページすらブランドの遊び場にする尖った設計。