表示例
アイコン: Font Awesome 7 Free(fa-solid / fa-regular)
別名・英語表記
- メッセージバブル
- チャットバブル
- 会話表示
- チャットログ
- トーク画面
- Chat message
実装例
<div class="x-chat-message">
<!-- role="log" は aria-live="polite" を暗黙に持つ。新しいメッセージを末尾に足すと、その分だけ読み上げる -->
<div class="x-chat-message__log" role="log" aria-label="サポートとの会話">
<div class="x-chat-message__row">
<span class="x-chat-message__av" aria-hidden="true"><i class="fa-solid fa-robot"></i></span>
<div class="x-chat-message__body">
<p class="x-chat-message__meta">サポート <time datetime="2026-09-25T10:02">10:02</time></p>
<p class="x-chat-message__bubble">ご用件をお聞かせください。</p>
</div>
</div>
<div class="x-chat-message__row x-chat-message__row--me">
<div class="x-chat-message__body">
<!-- 自分の名前は画面に出さないが、読み上げでは誰の発言かを伝える -->
<p class="x-chat-message__meta"><span class="x-chat-message__sr">あなた</span> <time datetime="2026-09-25T10:03">10:03</time></p>
<p class="x-chat-message__bubble">注文した品がまだ届きません</p>
</div>
</div>
</div>
<!-- 入力中の表示はログの外に置く。ログの中で出し入れすると、そのたびに読み上げられる -->
<p class="x-chat-message__typing">
<span class="x-chat-message__dots" aria-hidden="true"><span></span><span></span><span></span></span>
サポートが入力中
</p>
</div>
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-chat-message,
.x-chat-message *:not([class*="fa-"]),
.x-chat-message *:not([class*="fa-"])::before,
.x-chat-message *:not([class*="fa-"])::after {
box-sizing: border-box;
/* 貼った先の既定の書体に引きずられないようにする。書体が変わると
文字の幅と高さが変わり、枠のサイズまでずれる */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}
.x-chat-message {
position: relative;
width: 300px;
padding: 12px;
border: 1px solid #e3e6ea;
border-radius: 10px;
background: #fff;
}
.x-chat-message__log {
display: flex;
flex-direction: column;
gap: 10px;
}
.x-chat-message__row {
display: flex;
align-items: flex-start;
gap: 8px;
max-width: 85%;
}
/* 自分の発言は右に寄せる。左右の位置と色の両方で、誰の発言かを見分けさせる */
.x-chat-message__row--me {
align-self: flex-end;
}
.x-chat-message__av {
display: grid;
place-items: center;
flex: none;
width: 30px;
height: 30px;
border-radius: 50%;
background: #e8efff;
color: #1d4ed8;
font-size: 14px;
}
.x-chat-message__body {
display: flex;
flex-direction: column;
min-width: 0;
}
.x-chat-message__row--me .x-chat-message__body {
align-items: flex-end;
}
.x-chat-message__meta {
margin: 0 0 3px;
color: #5b6472;
font-size: 11px;
}
.x-chat-message__bubble {
margin: 0;
padding: 8px 12px;
border-radius: 4px 14px 14px 14px;
background: #eef0f3;
color: #1b2028;
font-size: 13px;
line-height: 1.6;
overflow-wrap: anywhere;
}
.x-chat-message__row--me .x-chat-message__bubble {
border-radius: 14px 4px 14px 14px;
background: #1d4ed8;
color: #fff;
}
/* 画面には出さず、読み上げにだけ渡す */
.x-chat-message__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.x-chat-message__typing {
display: flex;
align-items: center;
gap: 6px;
margin: 10px 0 0;
color: #5b6472;
font-size: 11px;
}
.x-chat-message__dots {
display: inline-flex;
gap: 3px;
padding: 6px 8px;
border-radius: 10px;
background: #eef0f3;
}
.x-chat-message__dots span {
width: 5px;
height: 5px;
border-radius: 50%;
background: #5b6472;
animation: x-chat-message-dot 1.2s infinite ease-in-out;
}
.x-chat-message__dots span:nth-child(2) {
animation-delay: 0.15s;
}
.x-chat-message__dots span:nth-child(3) {
animation-delay: 0.3s;
}
@keyframes x-chat-message-dot {
0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
30% { opacity: 1; transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) {
.x-chat-message__dots span {
animation: none;
opacity: 0.7;
}
}
AIへの指示文
「チャットのメッセージ(Chat message)」を実装してください。
## これは何か
会話を角の丸い枠で1通ずつ積み上げる表示。自分の発言は右に色つきで、相手は左にアイコンつきで並び、時刻や「入力中」の動く点が添う。
## 使いどころ
- 問い合わせ窓口やサポートのチャット、AIとの対話画面
- 2人以上のやり取りを、発言の順に追えるように見せたいとき
## 実装の要件
- div[role=log][aria-label] の中に、1通ずつ「名前と時刻 + 本文の枠」を積む。自分の発言は右寄せにする
- 枠の最大幅は親の8割ほどに留め、左右どちらの発言かが形でも分かるようにする
- 新着は末尾に足す(log は足された分を読み上げる)
- 誰の発言かを色だけで分けない。左右の位置・アイコン・名前のどれかを併せる
- 新しいメッセージが来るたびに一番下へ強制スクロールしない。過去を読み返している最中なら位置を保ち、「新しいメッセージ」の案内を出す
- 長いURLや英数字の続く文字列で枠が横にはみ出す。overflow-wrap: anywhere で折り返す
- 送信に失敗したメッセージを黙って消さない。枠に失敗の印と再送の操作を付けて残す
## アクセシビリティの要件
- メッセージを並べる領域に role="log" と aria-label を付ける。log は aria-live="polite" を暗黙に持ち、末尾に足した分を読み上げる
- 各メッセージに発言者の名前を入れる。画面に出さない自分の名前も、視覚的に隠した文字で読み上げに渡す
- 時刻は time 要素にして、datetime に機械で読める日時を書く
- 「入力中」の表示はログの外に置く。ログの中で出し入れすると、そのたびに読み上げられる
- 点が動くアニメーションは prefers-reduced-motion のときに止める
## 参考にする実装
この形を出発点にして、プロジェクトの命名規則・色・余白に合わせて調整してください。
```html
<div class="x-chat-message">
<!-- role="log" は aria-live="polite" を暗黙に持つ。新しいメッセージを末尾に足すと、その分だけ読み上げる -->
<div class="x-chat-message__log" role="log" aria-label="サポートとの会話">
<div class="x-chat-message__row">
<span class="x-chat-message__av" aria-hidden="true"><i class="fa-solid fa-robot"></i></span>
<div class="x-chat-message__body">
<p class="x-chat-message__meta">サポート <time datetime="2026-09-25T10:02">10:02</time></p>
<p class="x-chat-message__bubble">ご用件をお聞かせください。</p>
</div>
</div>
<div class="x-chat-message__row x-chat-message__row--me">
<div class="x-chat-message__body">
<!-- 自分の名前は画面に出さないが、読み上げでは誰の発言かを伝える -->
<p class="x-chat-message__meta"><span class="x-chat-message__sr">あなた</span> <time datetime="2026-09-25T10:03">10:03</time></p>
<p class="x-chat-message__bubble">注文した品がまだ届きません</p>
</div>
</div>
</div>
<!-- 入力中の表示はログの外に置く。ログの中で出し入れすると、そのたびに読み上げられる -->
<p class="x-chat-message__typing">
<span class="x-chat-message__dots" aria-hidden="true"><span></span><span></span><span></span></span>
サポートが入力中
</p>
</div>
```
```css
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-chat-message,
.x-chat-message *:not([class*="fa-"]),
.x-chat-message *:not([class*="fa-"])::before,
.x-chat-message *:not([class*="fa-"])::after {
box-sizing: border-box;
/* 貼った先の既定の書体に引きずられないようにする。書体が変わると
文字の幅と高さが変わり、枠のサイズまでずれる */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}
.x-chat-message {
position: relative;
width: 300px;
padding: 12px;
border: 1px solid #e3e6ea;
border-radius: 10px;
background: #fff;
}
.x-chat-message__log {
display: flex;
flex-direction: column;
gap: 10px;
}
.x-chat-message__row {
display: flex;
align-items: flex-start;
gap: 8px;
max-width: 85%;
}
/* 自分の発言は右に寄せる。左右の位置と色の両方で、誰の発言かを見分けさせる */
.x-chat-message__row--me {
align-self: flex-end;
}
.x-chat-message__av {
display: grid;
place-items: center;
flex: none;
width: 30px;
height: 30px;
border-radius: 50%;
background: #e8efff;
color: #1d4ed8;
font-size: 14px;
}
.x-chat-message__body {
display: flex;
flex-direction: column;
min-width: 0;
}
.x-chat-message__row--me .x-chat-message__body {
align-items: flex-end;
}
.x-chat-message__meta {
margin: 0 0 3px;
color: #5b6472;
font-size: 11px;
}
.x-chat-message__bubble {
margin: 0;
padding: 8px 12px;
border-radius: 4px 14px 14px 14px;
background: #eef0f3;
color: #1b2028;
font-size: 13px;
line-height: 1.6;
overflow-wrap: anywhere;
}
.x-chat-message__row--me .x-chat-message__bubble {
border-radius: 14px 4px 14px 14px;
background: #1d4ed8;
color: #fff;
}
/* 画面には出さず、読み上げにだけ渡す */
.x-chat-message__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.x-chat-message__typing {
display: flex;
align-items: center;
gap: 6px;
margin: 10px 0 0;
color: #5b6472;
font-size: 11px;
}
.x-chat-message__dots {
display: inline-flex;
gap: 3px;
padding: 6px 8px;
border-radius: 10px;
background: #eef0f3;
}
.x-chat-message__dots span {
width: 5px;
height: 5px;
border-radius: 50%;
background: #5b6472;
animation: x-chat-message-dot 1.2s infinite ease-in-out;
}
.x-chat-message__dots span:nth-child(2) {
animation-delay: 0.15s;
}
.x-chat-message__dots span:nth-child(3) {
animation-delay: 0.3s;
}
@keyframes x-chat-message-dot {
0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
30% { opacity: 1; transform: translateY(-3px); }
}
@media (prefers-reduced-motion: reduce) {
.x-chat-message__dots span {
animation: none;
opacity: 0.7;
}
}
```
## 出力の約束
- HTML と CSS を分けて出す。JavaScript が要るときは素の JavaScript で書き、UIフレームワークは使わない。
- 参考実装がアイコンに Font Awesome のクラスを使っている場合は、プロジェクトで使っているアイコンかインライン SVG に置き換えてよい。
- 上のアクセシビリティ要件を満たす。満たせない箇所があるときは、理由を添えて先に知らせる。
- 色・角丸・余白は既存のデザイントークンがあればそれを使う。無ければ CSS 変数として切り出す。
使いどころ
- 問い合わせ窓口やサポートのチャット、AIとの対話画面
- 2人以上のやり取りを、発言の順に追えるように見せたいとき
注意点
- 誰の発言かを色だけで分けない。左右の位置・アイコン・名前のどれかを併せる
- 新しいメッセージが来るたびに一番下へ強制スクロールしない。過去を読み返している最中なら位置を保ち、「新しいメッセージ」の案内を出す
- 長いURLや英数字の続く文字列で枠が横にはみ出す。overflow-wrap: anywhere で折り返す
- 送信に失敗したメッセージを黙って消さない。枠に失敗の印と再送の操作を付けて残す
アクセシビリティの要点
- メッセージを並べる領域に role="log" と aria-label を付ける。log は aria-live="polite" を暗黙に持ち、末尾に足した分を読み上げる
- 各メッセージに発言者の名前を入れる。画面に出さない自分の名前も、視覚的に隠した文字で読み上げに渡す
- 時刻は time 要素にして、datetime に機械で読める日時を書く
- 「入力中」の表示はログの外に置く。ログの中で出し入れすると、そのたびに読み上げられる
- 点が動くアニメーションは prefers-reduced-motion のときに止める