06드롭 말풍선 후기
후기는 물방울 꼬리가 달린 둥근 말풍선에 담고, 옆의 아바타는 과육 무늬 동그라미입니다. 말풍선이 젤리처럼 세로로 살짝 눌렸다 펴지기를 반복해 페이지 전체가 상큼하게 통통거려 보입니다.
쓰임고객 후기, 리뷰 한 줌
꼬리 말풍선과육 아바타squish 루프

<main class="stage">
<figure class="quotecitrus">
<span class="quotecitrus__avatar" aria-hidden="true"></span>
<div class="quotecitrus__bubble">
<blockquote class="quotecitrus__text">
<p class="quotecitrus__line">이 사이트 진짜 상큼해요</p>
</blockquote>
<figcaption class="quotecitrus__who">박모찌 · 스무디 가게 운영</figcaption>
</div>
</figure>
</main>@use "../../../../site/static/demo-tokens" as *;
$duration: $dur-loop; // 말풍선이 한 번 눌렸다 펴지는 주기
$easing: $ease-spring;
$color: $stage-ink;
$citrus-cream: #fffaf0;
$citrus-orange: #d8c1b1;
$citrus-orange-deep: #bd967a;
$citrus-lime: #c4ce9c;
$citrus-grapefruit: #ebd6da;
$citrus-lemon: #dfd8be;
$citrus-ink: #204a17;
// 무대 — 자몽 물색
@include stage(mix($citrus-grapefruit, $stage-paper, 22%));
.quotecitrus {
box-sizing: border-box;
width: clamp(280px, 90vw, 420px);
margin: 0;
display: flex;
align-items: flex-start;
gap: $sp-3;
}
// 과육 무늬 아바타
.quotecitrus__avatar {
flex: 0 0 auto;
width: clamp(44px, 12vw, 56px);
aspect-ratio: 1;
border-radius: 50%;
background: repeating-conic-gradient($citrus-orange 0deg 60deg, $citrus-lemon 60deg 120deg);
box-shadow: inset 0 -4px 8px rgba($citrus-ink, .16), 0 6px 14px rgba($citrus-orange-deep, .45);
animation: avatarBob $duration $easing infinite;
animation-delay: calc($duration / -2);
}
.quotecitrus__bubble {
position: relative;
flex: 1 1 auto;
min-width: 0;
box-sizing: border-box;
padding: $sp-4;
border-radius: $r-card;
background: $stage-paper;
box-shadow: 0 8px 20px rgba($citrus-grapefruit, .55);
animation: bubbleSquish $duration $easing infinite;
}
// 말풍선 꼬리 — 물방울 모양(비대칭 반경) 하나를 45도 돌려 붙인다
.quotecitrus__bubble::before {
content: "";
position: absolute;
top: $sp-3;
left: calc($sp-2 * -1);
width: $sp-4;
aspect-ratio: 1;
border-radius: 50% 50% 50% $r-xs;
background: $stage-paper;
transform: rotate(45deg);
}
.quotecitrus__text {
margin: 0;
}
.quotecitrus__line {
margin: 0;
color: $citrus-ink;
font-weight: 700; font-size: clamp(13px, 3.4vw, 16px); line-height: 1.4;
font-family: inherit;
}
.quotecitrus__who {
margin: $sp-2 0 0;
color: rgba($citrus-ink, .78);
font-weight: 500; font-size: clamp(10px, 2.6vw, 12px); line-height: 1;
font-family: inherit;
}
// 데모: 말풍선은 젤리처럼 세로로 살짝 눌렸다 펴지고, 아바타는 반대 위상으로 떠오른다
@keyframes bubbleSquish {
0%, 100% { transform: scaleY(1); }
50% { transform: scaleY(.94); }
}
@keyframes avatarBob {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
@media (prefers-reduced-motion: reduce) {
.quotecitrus__bubble, .quotecitrus__avatar { animation: none !important; transform: none; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: rgb(98.2745098039%, 96.462745098%, 96.8078431373%);
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.quotecitrus {
box-sizing: border-box;
width: clamp(280px, 90vw, 420px);
margin: 0;
display: flex;
align-items: flex-start;
gap: 12px;
}
.quotecitrus__avatar {
flex: 0 0 auto;
width: clamp(44px, 12vw, 56px);
aspect-ratio: 1;
border-radius: 50%;
background: repeating-conic-gradient(#d8c1b1 0deg 60deg, #dfd8be 60deg 120deg);
box-shadow: inset 0 -4px 8px rgba(32, 74, 23, 0.16), 0 6px 14px rgba(189, 150, 122, 0.45);
animation: avatarBob 2s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
animation-delay: -1s;
}
.quotecitrus__bubble {
position: relative;
flex: 1 1 auto;
min-width: 0;
box-sizing: border-box;
padding: 16px;
border-radius: 16px;
background: #ffffff;
box-shadow: 0 8px 20px rgba(235, 214, 218, 0.55);
animation: bubbleSquish 2s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
}
.quotecitrus__bubble::before {
content: "";
position: absolute;
top: 12px;
left: -8px;
width: 16px;
aspect-ratio: 1;
border-radius: 50% 50% 50% 4px;
background: #ffffff;
transform: rotate(45deg);
}
.quotecitrus__text {
margin: 0;
}
.quotecitrus__line {
margin: 0;
color: #204a17;
font-weight: 700;
font-size: clamp(13px, 3.4vw, 16px);
line-height: 1.4;
font-family: inherit;
}
.quotecitrus__who {
margin: 8px 0 0;
color: rgba(32, 74, 23, 0.78);
font-weight: 500;
font-size: clamp(10px, 2.6vw, 12px);
line-height: 1;
font-family: inherit;
}
@keyframes bubbleSquish {
0%, 100% {
transform: scaleY(1);
}
50% {
transform: scaleY(0.94);
}
}
@keyframes avatarBob {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-8px);
}
}
@media (prefers-reduced-motion: reduce) {
.quotecitrus__bubble, .quotecitrus__avatar {
animation: none !important;
transform: none;
}
}import type { CSSProperties } from "react";
import styles from "./TestimonialCitrus.module.scss";
export type TestimonialCitrusProps = {
quote?: string;
who?: string;
duration?: number;
easing?: string;
color?: string;
};
type Vars = CSSProperties & { "--duration"?: string; "--easing"?: string; "--color"?: string };
export default function TestimonialCitrus({
quote = "이 사이트 진짜 상큼해요",
who = "박모찌 · 스무디 가게 운영",
duration = 2000,
easing = "cubic-bezier(.2,.8,.2,1)",
color = "#ff9a52",
}: TestimonialCitrusProps) {
const vars: Vars = { "--duration": `${duration}ms`, "--easing": easing, "--color": color };
return (
<figure className={styles.quotecitrus} style={vars}>
<span className={styles.avatar} aria-hidden="true" />
<div className={styles.bubble}>
<blockquote className={styles.text}>
<p className={styles.line}>{quote}</p>
</blockquote>
<figcaption className={styles.who}>{who}</figcaption>
</div>
</figure>
);
}06 드롭 말풍선 후기 — 측정 누적면적 3.087% · 움직인 프레임 12/23GODRICH 원작 · zip 에 SCSS·React 포함 · 청량한 디자인 랜딩 UI 키트, 시트러스 컬러 섹션 9개
이 데모가 속한 글
청량한 디자인 랜딩 UI 키트, 시트러스 컬러 섹션 9개청량한 디자인은 오렌지·라임·자몽·레몬처럼 채도 높은 과일 색을 크림 바탕 위에 얹고, 카드마다 같은 계열의 진한 색 그림자를 드리워 파스텔보다 더 쨍하고 여름 음료 브랜드처럼 싱그럽게 보이게 만드는 스타일입니다. 이 글의 데모 전부 보기


