06Trượt trích dẫn trả lời
Đoạn trích dẫn trượt vào từ bên trái qua translateX, gắn lên trên tin nhắn trả lời.
Dùng choChat dạng thread trả lời một tin cụ thể, trả lời review hoặc bình luận
translateXborder-left0.15초

<main class="stage">
<div class="bubble">
<div class="quote is-demo">Ăn tối gì đây</div>
<p class="reply">Gà rán không?</p>
</div>
</main>@use "../../../../site/static/demo-tokens" as *;
// ── 변수 3개 ──────────────────────────────────────────────
$duration: $dur-quick; // 인용 조각이 밀려 들어오는 데 걸리는 시간
$easing: $ease-out;
$color: $subject-ink; // 말풍선 색 (yellow 무대라 ink)
@include stage($stage-yellow);
.bubble {
width: min(260px, 84vw);
padding: 14px 18px;
border-radius: $r-card;
background: $color;
color: #fff;
}
.quote {
padding: 14px 14px;
margin-bottom: 10px;
border-radius: 8px;
border-left: 3px solid $subject-cream;
background: rgba(255, 255, 255, .1);
font-weight: 500; font-size: clamp(13px, 3.8vw, 14px); line-height: 1.5; font-family: inherit;
color: rgba(255, 255, 255, .75);
&.is-demo { animation: quote-in-loop $dur-loop $easing infinite; }
}
.reply {
margin: 0;
font-weight: 600; font-size: clamp(14px, 4.2vw, 16px); line-height: 1.4; font-family: inherit;
}
// 인용 조각이 왼쪽에서 살짝 밀려 들어와 유지되다 다음 주기를 위해 사라진다
@keyframes quote-in-loop {
0% { transform: translateX(-18px); opacity: 0; }
22% { transform: translateX(0); opacity: 1; }
80% { transform: translateX(0); opacity: 1; }
95% { transform: translateX(-18px); opacity: 0; }
100% { transform: translateX(-18px); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.quote.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: #ffd23f;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.bubble {
width: min(260px, 84vw);
padding: 14px 18px;
border-radius: 16px;
background: #17141a;
color: #fff;
}
.quote {
padding: 14px 14px;
margin-bottom: 10px;
border-radius: 8px;
border-left: 3px solid #fff7e6;
background: rgba(255, 255, 255, 0.1);
font-weight: 500;
font-size: clamp(13px, 3.8vw, 14px);
line-height: 1.5;
font-family: inherit;
color: rgba(255, 255, 255, 0.75);
}
.quote.is-demo {
animation: quote-in-loop 2s ease-out infinite;
}
.reply {
margin: 0;
font-weight: 600;
font-size: clamp(14px, 4.2vw, 16px);
line-height: 1.4;
font-family: inherit;
}
@keyframes quote-in-loop {
0% {
transform: translateX(-18px);
opacity: 0;
}
22% {
transform: translateX(0);
opacity: 1;
}
80% {
transform: translateX(0);
opacity: 1;
}
95% {
transform: translateX(-18px);
opacity: 0;
}
100% {
transform: translateX(-18px);
opacity: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.quote.is-demo {
animation: none !important;
transform: none;
opacity: 1;
}
}import type { CSSProperties, ReactNode } from "react";
import styles from "./ReplyQuoteSlide.module.scss";
export type ReplyQuoteSlideProps = {
quote: string;
children: ReactNode;
/** 인용 조각이 밀려 들어오는 데 걸리는 시간 (기본 220ms) */
duration?: number;
easing?: string;
className?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string };
export default function ReplyQuoteSlide({
quote,
children,
duration = 220,
easing = "ease-out",
className = "",
}: ReplyQuoteSlideProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing };
return (
<div className={`${styles.bubble} ${className}`} style={vars}>
<div className={styles.quote}>{quote}</div>
<p className={styles.reply}>{children}</p>
</div>
);
}06 Trượt trích dẫn trả lời — Diện tích đo được 9.319% · khung hình chuyển động 10/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


