チャット · チャットUI
マンガの吹き出しで進むサポートチャット
太い輪郭線と尻尾付きの吹き出し、網掛けの紙地でサポート対話をマンガのコマとして見せるチャットUI。解決の瞬間だけ叫び吹き出しに切り替えて感情の起伏を作ります。
このブラウザー内に保存します。別の端末との同期はなく、サイトデータを消すと保存も消えます。
印刷時は見本を静止画にし、プロンプトと解説を出力します。PDF保存はブラウザーの印刷画面から選べます。
Vibehaus · デザイン資料
https://vibe.itlibra.com/design/comic-support-chat/
完全無料・著作権フリー(CC0)· 料金¥0 · 商用利用・改変自由
プレビュー
指定幅で実際に組み替えて表示します。表示領域より広い場合は、この枠の中で横へスクロールできます。
AIへの指示文
カスタマーサポートのチャット画面を、マンガの吹き出し表現で作ってください。 要件: - 配色: 生成りの紙 #fbf7ee、黒 #171412、トーン地 #e8e1d3、朱色 #ff5a3c、青 #2f6df6。 - 背景に -45度の細い網掛け(repeating-linear-gradient、不透明度0.045)を敷いてスクリーントーンを再現する。 - 全体を4pxの黒枠で囲み、右下に10pxのベタ影(box-shadow のオフセットのみ、ぼかし0)を落とす。 - 吹き出しは角丸20px + 3pxの黒輪郭。尻尾は疑似要素2枚(黒い三角の上に背景色の三角を重ねる)で作る。 - 相手の吹き出しは左に尻尾、自分の吹き出しは右に尻尾+グレー地。 - 解決した瞬間の1コマだけ「叫び吹き出し」にする: 朱色ベタ、白抜き太字、-1.2度の傾き、角の一つだけ尖らせる。 - 擬音(ドン!)を斜めに配置し、朱色の極太で置く。 - ヘッダーに担当者アバター(CSSだけで目と口を描く)、名前、平均返信時間、「EP.12 / P.3」のページ番号。 - 定型返答のボタンはピル型・3px輪郭・3pxのベタ影、押すと影が消えて沈む。 - フォントは丸ゴシック優先。日本語の letter-spacing は0、本文の行間1.8。
バリエーション
4コマ完結版
吹き出しを4つに固定し、縦に均等な4コマとして枠線で仕切る。 よくある質問の回答を4コマで見せる用途に使う。
モノクロ劇画版
朱色を捨てて黒白のみにし、網掛けを濃くする。 吹き出しの輪郭を手描き風の不均一な太さにして、深刻な問い合わせにも耐える硬さを出す。
このプレビューのコード
HTMLとCSSの1ファイルです。外部依存・広告・解析コードはありません。マンガ風のサポート画面の表示見本です。選択肢・送信・請求書再発行・メール配信は実装していません。
コードを表示
<!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: #fbf7ee;
--ink: #171412;
--tone: #e8e1d3;
--accent: #ff5a3c;
--accent-2: #2f6df6;
--dim: #6f6759;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
min-height: 100vh;
font-family: "Hiragino Maru Gothic ProN", "Hiragino Kaku Gothic ProN",
"Noto Sans JP", "Yu Gothic", "Meiryo", "Inter", sans-serif;
color: var(--ink);
line-height: 1.8;
background:
repeating-linear-gradient(
-45deg,
rgba(23, 20, 18, 0.045) 0 2px,
transparent 2px 7px
),
var(--paper);
display: flex;
justify-content: center;
padding: clamp(1rem, 3vw, 2rem);
-webkit-font-smoothing: antialiased;
}
.book {
width: min(720px, 100%);
background: var(--paper);
border: 4px solid var(--ink);
box-shadow: 10px 10px 0 0 var(--ink);
display: flex;
flex-direction: column;
}
header.strip {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0.75rem 1rem;
border-bottom: 4px solid var(--ink);
background: var(--accent);
color: var(--paper);
}
header .who { display: flex; align-items: center; gap: 0.6rem; }
.avatar {
width: 34px; height: 34px;
border: 3px solid var(--ink);
border-radius: 50%;
background: var(--paper);
position: relative;
}
.avatar::before, .avatar::after {
content: "";
position: absolute;
top: 11px;
width: 4px; height: 5px;
background: var(--ink);
border-radius: 2px;
}
.avatar::before { left: 8px; }
.avatar::after { right: 8px; }
.avatar i {
position: absolute;
bottom: 7px; left: 50%;
transform: translateX(-50%);
width: 12px; height: 6px;
border: 3px solid var(--ink);
border-top: 0;
border-radius: 0 0 12px 12px;
}
header .name { font-weight: 800; font-size: 0.95rem; line-height: 1.5; }
header .status { font-size: 0.72rem; line-height: 1.6; opacity: 0.9; }
header .page {
font-family: "JetBrains Mono", ui-monospace, monospace;
font-size: 0.68rem;
letter-spacing: 0.14em;
}
.panels {
padding: 1.1rem 1rem 0.5rem;
display: grid;
gap: 1.1rem;
}
.turn { display: grid; gap: 0.35rem; }
.turn .meta {
font-family: "JetBrains Mono", ui-monospace, monospace;
font-size: 0.68rem;
letter-spacing: 0; /* 話者名は和文。トラッキングを開かない */
color: var(--dim);
}
/* Speech balloon — hard outline + a tail cut from two triangles. */
.balloon {
position: relative;
max-width: 86%;
padding: 0.85rem 1.05rem;
border: 3px solid var(--ink);
border-radius: 20px;
background: var(--paper);
font-size: 0.95rem;
line-height: 1.8;
}
.balloon::before, .balloon::after {
content: "";
position: absolute;
bottom: -17px;
width: 0; height: 0;
border-style: solid;
}
/* agent (left) */
.agent .balloon { background: #fff; }
.agent .balloon::before {
left: 26px;
border-width: 17px 15px 0 0;
border-color: var(--ink) transparent transparent transparent;
}
.agent .balloon::after {
left: 30px;
bottom: -12px;
border-width: 12px 10px 0 0;
border-color: #fff transparent transparent transparent;
}
/* user (right) */
.user { justify-items: end; }
.user .meta { text-align: right; }
.user .balloon {
background: var(--tone);
border-radius: 20px;
}
.user .balloon::before {
right: 26px;
border-width: 17px 0 0 15px;
border-color: var(--ink) transparent transparent transparent;
}
.user .balloon::after {
right: 30px;
bottom: -12px;
border-width: 12px 0 0 10px;
border-color: var(--tone) transparent transparent transparent;
}
/* Shout balloon for the resolved moment. */
.shout .balloon {
background: var(--accent);
color: var(--paper);
border-width: 4px;
border-radius: 26px 26px 26px 6px;
font-weight: 800;
transform: rotate(-1.2deg);
}
.shout .balloon::after { border-color: var(--accent) transparent transparent transparent; }
/* The sound effect sits outside the balloon, the way it does on a
printed page — never squeezed into the line of dialogue. */
.shout { position: relative; }
.sfx {
position: absolute;
right: 4px;
top: 6px;
font-weight: 900;
font-size: clamp(1.3rem, 4vw, 1.8rem);
line-height: 1.4;
color: var(--accent);
-webkit-text-stroke: 2px var(--ink);
paint-order: stroke fill;
transform: rotate(-8deg);
}
.choices {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
padding: 0.25rem 1rem 1rem;
}
.choice {
font: inherit;
font-size: 0.85rem;
line-height: 1.6;
font-weight: 700;
padding: 0.5rem 0.95rem;
border: 3px solid var(--ink);
border-radius: 999px;
background: var(--paper);
cursor: pointer;
box-shadow: 3px 3px 0 0 var(--ink);
transition: transform 0.08s, box-shadow 0.08s, background 0.15s;
}
.choice:hover { background: #ffe9a8; }
.choice:active { transform: translate(3px, 3px); box-shadow: none; }
.composer {
display: flex;
gap: 0.6rem;
padding: 0.85rem 1rem;
border-top: 4px solid var(--ink);
background: var(--tone);
}
.composer input {
flex: 1;
font: inherit;
font-size: 0.95rem;
line-height: 1.7;
padding: 0.6rem 0.9rem;
border: 3px solid var(--ink);
border-radius: 999px;
background: var(--paper);
color: var(--ink);
}
.composer input:focus { outline: none; box-shadow: 0 0 0 3px rgba(255, 90, 60, 0.35); }
.composer button {
font: inherit;
font-size: 0.9rem;
font-weight: 800;
padding: 0.6rem 1.2rem;
border: 3px solid var(--ink);
border-radius: 999px;
background: var(--accent-2);
color: var(--paper);
cursor: pointer;
box-shadow: 3px 3px 0 0 var(--ink);
}
.composer button:active { transform: translate(3px, 3px); box-shadow: none; }
@media (max-width: 520px) {
.book { box-shadow: 6px 6px 0 0 var(--ink); }
.balloon { max-width: 94%; }
}
button { min-height:44px; }
:focus-visible { outline:3px solid var(--accent-2); outline-offset:3px; }
.composer input { min-width:0; }
.balloon { overflow-wrap:anywhere; }
.demo-note { margin:0; padding:8px 16px; font-size:12px; line-height:1.8; }
@media (prefers-reduced-motion:reduce) { .choice { transition:none; } }
</style>
</head>
<body>
<div class="book">
<header class="strip">
<div class="who">
<span class="avatar" aria-hidden="true"><i></i></span>
<div>
<div class="name">サポートの ばん さん</div>
<div class="status">ただいま対応中 · 平均返信 40秒</div>
</div>
</div>
<span class="page">EP.12 / P.3</span>
</header>
<p class="demo-note">架空の対話の表示見本です。選択肢・送信は未実装で、請求書やメールは扱いません。</p>
<div class="panels">
<div class="turn agent">
<span class="meta">ばん · 16:02</span>
<div class="balloon">こんにちは! 今日はどうされましたか?</div>
</div>
<div class="turn user">
<span class="meta">あなた · 16:03</span>
<div class="balloon">先月の請求書がダウンロードできなくて困っています……</div>
</div>
<div class="turn agent">
<span class="meta">ばん · 16:03</span>
<div class="balloon">
承知しました! 請求書は「設定 → お支払い」から取得できます。該当の月は 2026年7月 でお間違いないですか?
</div>
</div>
<div class="turn user">
<span class="meta">あなた · 16:04</span>
<div class="balloon">はい、7月分です。</div>
</div>
<div class="turn agent shout">
<span class="meta">ばん · 16:04</span>
<span class="sfx" aria-hidden="true">ドン!</span>
<div class="balloon">
見つかりました! いま再発行して、登録のメールにお送りしました
</div>
</div>
</div>
<div class="choices">
<button class="choice" type="button">届きました、ありがとう</button>
<button class="choice" type="button">まだ届きません</button>
<button class="choice" type="button">別の件も聞きたい</button>
</div>
<form class="composer" onsubmit="return false;">
<input type="text" placeholder="メッセージを入力…" aria-label="メッセージ" />
<button type="submit">送る</button>
</form>
</div>
</body>
</html>
2026年10月14日、Chromiumで320・390・768・1280pxの描画とキーボードのフォーカス表示を確認しました。他のブラウザは未確認です。利用先のブラウザと実データでも確認してください。
概要
日本のマンガは、吹き出しの形だけで声の質を描き分けてきました。丸い輪郭は通常の会話、爆発形は叫び、点線は内心、四角はナレーション。読者はこの記号体系を教わることなく身につけています。チャットUIにこれを持ち込むと、文字量を増やさずに感情の起伏を表現できます。
均一な吹き出しが失うもの
一般的なチャットUIでは、すべての発言が同じ形の角丸長方形で並びます。整然としていますが、対話の中で最も重要な瞬間——問題が解決した一言——も、事務的な確認と同じ見た目で流れていきます。この設計では、解決の1コマだけを叫び吹き出しに切り替えます。朱色のベタ、白抜きの太字、わずかな傾き、そして斜めの擬音。同じテキストでも、読んだ側の記憶への残り方が変わります。サポートの満足度は解決までの時間だけでは決まりません。解決したと感じられたかで決まります。
紙の質感が担保する人間味
背景の網掛けはスクリーントーンの再現です。無地の白背景よりわずかに情報量が増え、画面が印刷物に近づきます。4pxの黒枠と、ぼかしのないベタ影も同じ方向の意匠で、画面をコマとして扱う宣言になっています。ヘッダーの担当者アバターをCSSの図形だけで描いているのは、写真のアイコンより記号的な顔の方が親しみやすいためです。人は抽象化された顔に自分の期待を投影します。
仕上げの判断軸
向かないのは障害報告と解約の窓口です。困っている度合いが強い相手にマンガの軽さを当てると、真剣に扱われていないと読まれます。
同じ意匠でも彩度を落としたモノクロ版に切り替えるか、通常のチャットUIを併用してください。擬音の文字表現はマンガ文化圏の外では読み解けないため、装飾として置き、意味を担わせないこと。網掛けの不透明度は0.05前後が上限で、それ以上は本文の可読性を削ります。
チャットの構成要素
使いどころ
- 個人向けサービスのサポート窓口
- オンボーディング中のガイド対話
- エンタメ・ゲーム系プロダクトの問い合わせ
- チャットボットの回答画面
- 若年層が主要層のサービス
このデザインの分類
背景と狙いどころ
よくある質問
吹き出しの尻尾はどう作りますか?
深刻な問い合わせに軽すぎませんか?
擬音は日本語以外でも通じますか?
網掛け背景は読みにくくなりませんか?
この画面を実装する
動くサンプルとコピペできるコードを、技術別にまとめています。
関連するデザイン
既読と日付区切りのある和製トーク画面
日本のスマホで最も見慣れたトーク画面の文法を再現したチャットUI。青みの地に緑と白の吹き出し、吹き出しの外に置く時刻と既読の人数、日付の札、連投でしっぽと名前を省く組み方までを1枚にまとめる。
流れて出るAIアシスタントのチャット画面
左に会話の履歴、中央に質問と回答を並べるAIアシスタント型のチャット画面。回答が一文字ずつ流れて出る表示、生成の停止、コードのコピー、日本語入力の変換確定で誤送信しない入力欄までを1枚で再現する。
Discord/Slack風の3ペイン・チャット画面
Discord・Slack のチャットUIを再構築した3ペインインターフェイス。サーバーリスト+チャンネル+メッセージスレッド+リアクション・スレッドの定番構成を CSS だけで網羅する尖った設計。