DEMO
CODE
<div class="demo-stage tpi-stage">
<div class="tpi-chat" id="tpi-chat" role="log" aria-live="polite" aria-label="チャットのデモ">
<div class="tpi-msg tpi-me">こんにちは!</div>
</div>
</div>
.tpi-stage { display:flex; align-items:center; justify-content:center; padding:1.5rem; background:#0B0B10; min-height:280px; }
.tpi-chat { width:100%; max-width:340px; min-height:210px; display:flex; flex-direction:column; justify-content:flex-end; gap:.5rem; }
.tpi-msg { max-width:75%; padding:.6rem .9rem; border-radius:16px; font-size:.86rem; line-height:1.5; animation: tpi-in .3s cubic-bezier(.22,1,.36,1) both; }
.tpi-me { align-self:flex-end; background:#E91B89; color:#fff; border-bottom-right-radius:4px; }
.tpi-you { align-self:flex-start; background:#1E1E26; color:#EDEDED; border-bottom-left-radius:4px; }
.tpi-typing { align-self:flex-start; display:flex; gap:5px; padding:.8rem .9rem; border-radius:16px; border-bottom-left-radius:4px; background:#1E1E26; animation: tpi-in .3s ease both; }
.tpi-typing i { width:7px; height:7px; border-radius:50%; background:#9A9AA6; animation: tpi-bounce 1.2s ease-in-out infinite; }
.tpi-typing i:nth-child(2) { animation-delay:.15s; }
.tpi-typing i:nth-child(3) { animation-delay:.3s; }
@keyframes tpi-bounce { 0%, 60%, 100% { transform:translateY(0); opacity:.5; } 30% { transform:translateY(-6px); opacity:1; } }
@keyframes tpi-in { from { opacity:0; transform:translateY(8px) scale(.96); } to { opacity:1; transform:none; } }
@media (prefers-reduced-motion: reduce) {
.tpi-msg, .tpi-typing { animation:none; }
.tpi-typing i { animation:none; opacity:.8; }
}
(function(){
var chat = document.getElementById('tpi-chat');
if (!chat) return;
var SCRIPT = [
['you', 'こんにちは!ご用件を伺います。'],
['me', '予約の変更はできますか?'],
['you', 'はい、変更できます。ご希望の日時を教えてください。']
];
var step = 0;
function add(who, text){
var m = document.createElement('div');
m.className = 'tpi-msg tpi-' + who; m.textContent = text;
chat.appendChild(m);
while (chat.children.length > 4) chat.removeChild(chat.firstElementChild);
}
function next(){
if (step >= SCRIPT.length) {
step = 0;
setTimeout(function(){ chat.innerHTML = ''; add('me', 'こんにちは!'); setTimeout(next, 900); }, 2600);
return;
}
var s = SCRIPT[step++];
if (s[0] === 'you') {
var t = document.createElement('div');
t.className = 'tpi-typing'; t.setAttribute('aria-label', '相手が入力中');
t.innerHTML = '<i></i><i></i><i></i>';
chat.appendChild(t);
setTimeout(function(){ chat.removeChild(t); add('you', s[1]); setTimeout(next, 1000); }, 1600);
} else {
add('me', s[1]); setTimeout(next, 900);
}
}
setTimeout(next, 800);
})();
AI PROMPT
チャットで相手が入力中であることを示す Typing Indicator(3つの点が順番に弾む吹き出し)を作って。吹き出しの中に i 要素を3つ置き、@keyframes で 0%・60%・100% は translateY(0) で半透明、30% だけ translateY(-6px) で不透明にして1.2秒の無限ループにする。2つ目と3つ目に animation-delay を .15秒・.3秒ずつずらすと、波のように順番に弾む。デモでは会話の流れを再現する:相手の発言の前に入力中の吹き出しを1.6秒出し、それを取り除いてから返信を translateY(8px) scale(.96) → 元の位置 のアニメーションで表示する。自分の発言は右寄せでアクセント色、相手は左寄せで暗い色、発言者側の下の角だけ角丸を小さくする。表示する発言は最新4件までにして古いものから消す。チャット全体は role="log" aria-live="polite" にして新しい発言が読み上げられるようにし、入力中の吹き出しには aria-label="相手が入力中" を付ける。@media (prefers-reduced-motion: reduce) では点を弾ませずに静止表示する。 Acceptance criteria: works with prefers-reduced-motion (animation disabled), zero console errors, zero layout shift
AIエージェントでの実装ガイド → Claude Code でWebアニメーションを実装する
BOOKS · PR · AMAZON
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
学びを止めない · AMAZONサブスク
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
チャットやメッセージアプリで、相手が今まさに文章を打っていることを示す表示です。3つの点が順番に弾む吹き出しは多くのチャットで使われている形で、「返事が来る」ことが分かるため、待っている間に画面を離れにくくなります。
当サイトの Dots Pulse は点が脈打つ汎用の読み込み表示、Animated List は通知が積み重なるリストです。本ページはチャットの吹き出しの中に置く入力中の表示と、返信が現れるまでの流れを扱う別テーマで、サポートチャットやAIチャットの画面に使えます。
AIの応答を待つ画面では、入力中の表示が「処理が止まっていない」ことを伝える役割も持ちます。新しい発言を読み上げに伝える role="log" と組み合わせると、画面を見ていない利用者にも会話の進行が伝わります。
点の動きを translateY だけで作る理由は?
transform の translateY はレイアウトを再計算せずに位置だけを動かせるため、多数の吹き出しがある画面でも軽く動きます。margin や top を動かすと、点の上下にある要素まで毎フレーム位置が計算し直されます。不透明度の変化も合わせると、弾んでいる点がより目立ちます。
入力中の表示はどのくらいの時間出すのが自然ですか?
実際のチャットでは、相手の入力状況をサーバーから受け取って表示と非表示を切り替えます。自動応答やデモで演出として使う場合は、返信の長さに応じて1〜2秒程度にすると自然に見えます。短すぎると表示された瞬間に消えて気づかれず、長すぎると待たされている印象になります。
コードは無料で使えますか?
はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。