01Bong bóng bật hiện (pop-in)
Bong bóng tin nhắn mới phóng to từ scale nhỏ lên 1 kèm opacity, giống như vừa bật ra trên màn hình.
Dùng choTin nhắn mới trong chat 1:1, bong bóng xem trước bên trong toast thông báo
scale(0.8→1)opacity0.18초

<main class="stage">
<div class="bubble is-demo">Vừa đến!</div>
</main>@use "../../../../site/static/demo-tokens" as *;
// ── 변수 3개 ──────────────────────────────────────────────
$duration: $dur-quick; // 실제 등장(팝)이 끝나는 데 걸리는 시간 — React 판 --duration 기본값
$easing: $ease-pop; // 튀어나오듯 오버슈트 후 안착
$color: $subject-cream; // 말풍선 색 (ink 무대라 cream)
@include stage($stage-ink);
.bubble {
padding: 22px 34px;
border-radius: $r-card;
background: $color;
color: $stage-ink;
font-weight: 700; font-size: clamp(18px, 5.6vw, 24px); line-height: 1.4; font-family: inherit;
transform-origin: center;
&.is-demo {
animation: bubble-pop-loop $dur-loop $easing infinite;
}
}
// 한 주기(2s) 안에 팝 등장 → 유지 → 사라짐을 담아 gif 이음매가 안 보이게 한다
@keyframes bubble-pop-loop {
0% { transform: scale(.4); opacity: 0; }
16% { transform: scale(1.15); opacity: 1; }
24% { transform: scale(1); opacity: 1; }
82% { transform: scale(1); opacity: 1; }
100% { transform: scale(.4); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.bubble.is-demo { animation: none !important; transform: none; opacity: 1; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #17141a;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.bubble {
padding: 22px 34px;
border-radius: 16px;
background: #fff7e6;
color: #17141a;
font-weight: 700;
font-size: clamp(18px, 5.6vw, 24px);
line-height: 1.4;
font-family: inherit;
transform-origin: center;
}
.bubble.is-demo {
animation: bubble-pop-loop 2s cubic-bezier(0.2, 1.4, 0.4, 1) infinite;
}
@keyframes bubble-pop-loop {
0% {
transform: scale(0.4);
opacity: 0;
}
16% {
transform: scale(1.15);
opacity: 1;
}
24% {
transform: scale(1);
opacity: 1;
}
82% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(0.4);
opacity: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.bubble.is-demo {
animation: none !important;
transform: none;
opacity: 1;
}
}import type { CSSProperties, ReactNode } from "react";
import styles from "./BubblePopIn.module.scss";
export type BubblePopInProps = {
children: ReactNode;
/** 팝 등장이 끝나는 데 걸리는 시간 (기본 220ms) */
duration?: number;
/** easing (기본 오버슈트 포지션) */
easing?: string;
/** 말풍선 색 */
color?: string;
className?: string;
};
type Vars = CSSProperties & {
"--duration"?: string;
"--easing"?: string;
"--color"?: string;
};
export default function BubblePopIn({
children,
duration = 220,
easing = "cubic-bezier(.2, 1.4, .4, 1)",
color = "#fff7e6",
className = "",
}: BubblePopInProps) {
const vars: Vars = {
"--duration": `${duration}ms`,
"--easing": easing,
"--color": color,
};
return (
<div className={`${styles.bubble} ${styles.enter} ${className}`} style={vars}>
{children}
</div>
);
}01 Bong bóng bật hiện (pop-in) — Diện tích đo được 13.073% · khung hình chuyển động 8/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · 9 CSS Chat Bubble Animation — dán 1 dòng là chạy
Bài viết chứa demo này
9 CSS Chat Bubble Animation — dán 1 dòng là chạyCSS chat bubble animation là hiệu ứng bong bóng chat chạy bằng CSS thuần khi tin nhắn xuất hiện hoặc được xem. Chín kiểu Xem tất cả demo trong bài này


