07Nhấp nháy
`.a-flash` đưa opacity qua 1→0→1 hai lần liên tiếp, nhấp nháy rõ ràng mà chưa bao giờ khiến phần tử biến mất hẳn.
Dùng choIcon thông báo khẩn, chấm báo đang phát trực tiếp, badge cần lóe sáng
opacity2단 점멸1초

<main class="stage">
<div class="notice">
<span class="notice__dot a-flash" aria-hidden="true"></span>
Thông báo khẩn
</div>
</main>@use "../../../../site/static/demo-tokens" as *;
// ── 변수 3개 ──────────────────────────────────────────
$duration: 1s;
$easing: ease-in-out;
$color: $subject-cream;
// ── 데모 무대 ───────────────────────────────
@include stage($stage-orange);
.notice {
display: inline-flex;
align-items: center;
gap: 12px;
padding: 14px 28px;
border-radius: $r-pill;
background: rgba(255, 255, 255, .14);
color: $subject-ink; // AA: 주황 면(흰 14% 겹침 #d2ada4) 위 6.28:1 — 알림 점은 크림 유지
font-weight: 700; font-size: clamp(15px, 4vw, 18px); line-height: 1; font-family: inherit;
}
.notice__dot {
width: 16px;
height: 16px;
border-radius: 50%;
background: $color;
flex: none;
}
// ── .a-flash 는 opacity 만으로 두 번 끊어 깜빡인다. 요소는 사라지지 않는다 ─
.a-flash {
animation: flash $duration $easing infinite;
}
@keyframes flash {
0%, 50%, 100% { opacity: 1; }
25%, 75% { opacity: .15; }
}
@media (prefers-reduced-motion: reduce) {
.a-flash { animation: none; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ff4d1f;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.notice {
display: inline-flex;
align-items: center;
gap: 12px;
padding: 14px 28px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.14);
color: #17141a;
font-weight: 700;
font-size: clamp(15px, 4vw, 18px);
line-height: 1;
font-family: inherit;
}
.notice__dot {
width: 16px;
height: 16px;
border-radius: 50%;
background: #fff7e6;
flex: none;
}
.a-flash {
animation: flash 1s ease-in-out infinite;
}
@keyframes flash {
0%, 50%, 100% {
opacity: 1;
}
25%, 75% {
opacity: 0.15;
}
}
@media (prefers-reduced-motion: reduce) {
.a-flash {
animation: none;
}
}import type { CSSProperties, ReactNode } from "react";
import styles from "./FlashNotice.module.scss";
export type FlashNoticeProps = {
children: ReactNode;
/** 한 번 깜빡이는 데 걸리는 시간 (기본 1000ms) */
duration?: number;
/** CSS easing (기본 ease-in-out) */
easing?: string;
/** 점·글자 색 */
color?: string;
};
type Vars = CSSProperties & {
"--duration"?: string;
"--easing"?: string;
"--color"?: string;
};
export default function FlashNotice({
children,
duration = 1000,
easing = "ease-in-out",
color = "#fff7e6",
}: FlashNoticeProps) {
const vars: Vars = {
"--duration": `${duration}ms`,
"--easing": easing,
"--color": color,
};
return (
<div className={styles.notice} style={vars}>
<span className={styles.dot} aria-hidden="true" />
{children}
</div>
);
}07 Nhấp nháy — Diện tích đo được 0.15% · khung hình chuyển động 23/23Nguyên tác GODRICH · SCSS và React nằm trong tệp zip · 9 CSS Keyframe Animations — dán 1 dòng là chạy
Bài viết chứa demo này
9 CSS Keyframe Animations — dán 1 dòng là chạyCSS keyframe animation là chuyển động lặp được định nghĩa bằng @keyframes rồi gộp vào một class duy nhất, dán vào phần t Xem tất cả demo trong bài này


