04Bong bóng tin nhắn bật vào
Khi câu trả lời hoàn chỉnh, ô đang trống bật thành bong bóng với scale đi từ 0.85 lên 1 và opacity từ 0 lên 1, khiến việc trả lời đã tới rõ ràng không lẫn được.
Dùng choBong bóng trả lời hoàn chỉnh xuất hiện, toast thông báo bật vào
scaleopacitycubic-bezier

<main class="stage">
<div class="bp-bubble is-demo">Here's the summary you asked for.</div>
</main>@use "../../../../site/static/demo-tokens" as *;
// ── 변수 3개 ──────────────────────────────────────────
$duration: $dur-loop;
$easing: $ease-pop;
$color: $subject-blue-deep; // 크림 글자가 얹히므로 진한 파랑
@include stage($stage-paper);
.bp-bubble {
max-width: min(280px, 84vw);
padding: $sp-4 $sp-5;
border-radius: $r-card;
box-sizing: border-box;
background: $color;
color: $subject-cream;
font: 500 14px/1.5 -apple-system, "Segoe UI", sans-serif;
box-shadow: $shadow-press;
}
// 실사용: 답변이 도착하는 순간 한 번만 재생 (transitionend 뒤 그대로 유지)
@keyframes bp-pop {
0% { transform: scale(.82); opacity: 0; }
15% { transform: scale(1.05); opacity: 1; }
25% { transform: scale(1); opacity: 1; }
70% { transform: scale(1); opacity: 1; }
85% { transform: scale(.9); opacity: 0; }
100% { transform: scale(.82); opacity: 0; }
}
.bp-bubble.is-demo {
animation: bp-pop $duration $easing infinite;
}
@media (prefers-reduced-motion: reduce) {
.bp-bubble.is-demo {
animation: none !important;
transform: none !important;
opacity: 1 !important;
}
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ffffff;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.bp-bubble {
max-width: min(280px, 84vw);
padding: 16px 20px;
border-radius: 16px;
box-sizing: border-box;
background: #0a4fe8;
color: #fff7e6;
font: 500 14px/1.5 -apple-system, "Segoe UI", sans-serif;
box-shadow: 0 6px 12px rgba(23, 20, 26, 0.32);
}
@keyframes bp-pop {
0% {
transform: scale(0.82);
opacity: 0;
}
15% {
transform: scale(1.05);
opacity: 1;
}
25% {
transform: scale(1);
opacity: 1;
}
70% {
transform: scale(1);
opacity: 1;
}
85% {
transform: scale(0.9);
opacity: 0;
}
100% {
transform: scale(0.82);
opacity: 0;
}
}
.bp-bubble.is-demo {
animation: bp-pop 2s cubic-bezier(0.2, 1.4, 0.4, 1) infinite;
}
@media (prefers-reduced-motion: reduce) {
.bp-bubble.is-demo {
animation: none !important;
transform: none !important;
opacity: 1 !important;
}
}import { CSSProperties } from "react";
import styles from "./BubblePopIn.module.scss";
type Vars = CSSProperties & {
"--duration"?: string;
"--easing"?: string;
"--color"?: string;
};
export interface BubblePopInProps {
duration?: string;
easing?: string;
color?: string;
text?: string;
}
export default function BubblePopIn({
duration = "2s",
easing = "cubic-bezier(.2, 1.4, .4, 1)",
color = "#0a4fe8",
text = "Here's the summary you asked for.",
}: BubblePopInProps) {
const style: Vars = {
"--duration": duration,
"--easing": easing,
"--color": color,
};
return (
<div className={styles.bubble} style={style}>
{text}
</div>
);
}04 Bong bóng tin nhắn bật vào — Diện tích đo được 13.303% · khung hình chuyển động 8/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · 9 css loading animation cho AI chat, copy-paste
Bài viết chứa demo này
9 css loading animation cho AI chat, copy-pasteBa chấm nhấp nhô, con trỏ chớp tắt, chữ hiện dần lúc bạn chờ câu trả lời trong khung chat AI như ChatGPT hay Claude đều Xem tất cả demo trong bài này


