attention
انیمیشنهای هدفمند برای جلب توجه کاربر، اعلانها و هدایت تمرکز در رابط کاربری
این Skill مجموعهای از الگوهای CSS و JavaScript برای جلب توجه کاربر ارائه میدهد؛ از pulse، badge و ring pulse تا spotlight، shimmer، toast و راهنمای جهتدار. شدت انیمیشنها برای حالتهای subtle، moderate و urgent قابل تنظیم است.
با استفاده از این الگوها میتوانید اعلانها و تغییرات مهم را واضحتر نمایش دهید، بدون اینکه تجربه کاربری را مختل کنید. پشتیبانی از prefers-reduced-motion، امکان dismiss و ملاحظات WCAG به ساخت رابطهایی دسترسپذیر و حرفهای کمک میکند.
چه چیزی میگیرید
- الگوهای آماده برای pulse، notification badge، ring pulse و breathing glow
- افکتهای هدایت تمرکز مانند spotlight، arrow hint و highlight sweep
- انیمیشنهای shimmer برای loading و toast برای اعلانهای موقت
- راهنمای انتخاب شدت انیمیشن بر اساس اهمیت رویداد
- پیادهسازی جایگزین برای کاربران دارای `prefers-reduced-motion`
برای چه کاری خوب است
- طراحی داشبوردها و اپلیکیشنهایی که اعلان، بهروزرسانی یا وضعیت جدید دارند
- ساخت onboarding و تجربههایی که باید تمرکز کاربر را به یک بخش خاص هدایت کنند
- بهبود feedback بصری برای خطا، موفقیت، loading و محتوای تازه
برای چه کاری نیست
- انیمیشنهای پیچیده سینمایی، موشن گرافیک چندلایه یا تدوین ویدیو
- صفحههایی که به حرکت مداوم و جلب توجه شدید نیاز ندارند یا باید کاملاً ایستا باشند
دربارهٔ این اسکیل
Attention
Animations that direct and capture user attention.
Standards Reference
| Standard | Documentation |
|---|---|
| W3C DTCG | designtokens.org |
| WCAG 2.1 | w3.org/WAI/WCAG21/Understanding |
| Material Design | m3.material.io/foundations/interaction |
Quick Reference
Uses tokens from: tokens/motion.tokens.json
Attention Intensities
| Level | Duration | Use |
|---|---|---|
| Subtle | 2s cycle | Passive indication |
| Moderate | 1s cycle | Active notification |
| Urgent | 0.5s cycle | Critical alert |
Selection Guide
What attention level?
│
├── SUBTLE → Passive indication
│ ├── Gentle pulse → "something here"
│ ├── Soft glow → ambient highlight
│ └── Slow breathe → available action
│
├── MODERATE → Active notification
│ ├── Badge bounce → new content
│ ├── Pulse ring → update available
│ └── Shimmer → loading/processing
│
├── URGENT → Critical alert
│ ├── Rapid pulse → requires action
│ ├── Shake → error/warning
│ └── Flash → immediate attention
│
├── GUIDED → Focus direction
│ ├── Spotlight → isolated focus
│ ├── Arrow pulse → directional hint
│ └── Highlight sweep → scan guidance
│
└── CELEBRATION → Positive feedback
├── Confetti → achievement
├── Burst → success
└── Sparkle → reward
Patterns
Pulse Indicator
Gentle pulsing attention.
CSS:
.pulse {
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.05);
opacity: 0.8;
}
}
/* Urgent pulse */
.pulse-urgent {
animation: pulse-urgent 0.5s ease-in-out infinite;
}
@keyframes pulse-urgent {
0%, 100% {
transform: scale(1);
box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.7);
}
50% {
transform: scale(1.02);
box-shadow: 0 0 0 10px rgba(239, 68, 68, 0);
}
}
Notification Badge
Bouncing badge indicator.
CSS:
.badge {
position: absolute;
top: -8px;
right: -8px;
min-width: 20px;
height: 20px;
background: #ef4444;
border-radius: 10px;
color: white;
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.badge.new {
animation: badge-bounce 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes badge-bounce {
0% {
transform: scale(0);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
/* Continuous attention */
.badge.attention {
animation: badge-pulse 1s ease-in-out infinite;
}
@keyframes badge-pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.15);
}
}
JavaScript (Animate on count change):
function updateBadge(badge, count) {
const currentCount = parseInt(badge.textContent) || 0;
if (count > currentCount) {
badge.textContent = count;
badge.classList.remove('new');
void badge.offsetWidth; // Trigger reflow
badge.classList.add('new');
} else {
badge.textContent = count;
}
badge.style.display = count > 0 ? 'flex' : 'none';
}
Ring Pulse
Expanding ring effect.
CSS:
.ring-pulse {
position: relative;
}
.ring-pulse::before {
content: '';
position: absolute;
inset: -4px;
border: 2px solid #3b82f6;
border-radius: inherit;
animation: ring-expand 1.5s ease-out infinite;
}
@keyframes ring-expand {
0% {
transform: scale(1);
opacity: 1;
}
100% {
transform: scale(1.5);
opacity: 0;
}
}
/* Multiple rings */
.ring-pulse::after {
content: '';
position: absolute;
inset: -4px;
border: 2px solid #3b82f6;
border-radius: inherit;
animation: ring-expand 1.5s ease-out infinite 0.5s;
}
Spotlight Focus
Highlight specific element.
CSS:
.spotlight-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.7);
pointer-events: none;
opacity: 0;
transition: opacity 300ms;
}
.spotlight-overlay.active {
opacity: 1;
}
.spotlight-target {
position: relative;
z-index: 1001;
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7);
border-radius: 8px;
animation: spotlight-pulse 2s ease-in-out infinite;
}
@keyframes spotlight-pulse {
0%, 100% {
box-shadow:
0 0 0 9999px rgba(0, 0, 0, 0.7),
0 0 0 4px rgba(59, 130, 246, 0.5);
}
50% {
box-shadow:
0 0 0 9999px rgba(0, 0, 0, 0.7),
0 0 0 8px rgba(59, 130, 246, 0.3);
}
}
JavaScript:
function spotlight(element) {
const overlay = document.createElement('div');
overlay.className = 'spotlight-overlay';
document.body.appendChild(overlay);
requestAnimationFrame(() => {
overlay.classList.add('active');
element.classList.add('spotlight-target');
});
return {
dismiss: () => {
overlay.classList.remove('active');
element.classList.remove('spotlight-target');
setTimeout(() => overlay.remove(), 300);
}
};
}
Shimmer Loading
Skeleton loading shimmer.
CSS:
.shimmer {
background: linear-gradient(
90deg,
#f0f0f0 0%,
#e0e0e0 50%,
#f0f0f0 100%
);
background-size: 200% 100%;
animation: shimmer 1.5s linear infinite;
}
@keyframes shimmer {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
Directional Arrow
Pulsing directional hint.
CSS:
.arrow-hint {
animation: arrow-bounce 1s ease-in-out infinite;
}
/* Point down */
.arrow-hint.down {
animation-name: arrow-bounce-down;
}
@keyframes arrow-bounce-down {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(8px);
}
}
/* Point right */
.arrow-hint.right {
animation-name: arrow-bounce-right;
}
@keyframes arrow-bounce-right {
0%, 100% {
transform: translateX(0);
}
50% {
transform: translateX(8px);
}
}
Highlight Sweep
Scanning highlight effect.
CSS:
.highlight-sweep {
position: relative;
overflow: hidden;
}
.highlight-sweep::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 50%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.4),
transparent
);
animation: sweep 2s ease-in-out infinite;
}
@keyframes sweep {
0% {
left: -100%;
}
50%, 100% {
left: 200%;
}
}
Toast Notification
Attention-grabbing notification.
CSS:
.toast {
position: fixed;
bottom: 24px;
right: 24px;
padding: 16px 24px;
background: #1f2937;
color: white;
border-radius: 8px;
transform: translateY(100px);
opacity: 0;
transition: transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1),
opacity 300ms ease-out;
}
.toast.visible {
transform: translateY(0);
opacity: 1;
}
/* With progress bar */
.toast.auto-dismiss::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
height: 3px;
background: #3b82f6;
animation: toast-progress 5s linear forwards;
}
@keyframes toast-progress {
from { width: 100%; }
to { width: 0%; }
}
Breathing Glow
Ambient attention indicator.
CSS:
.breathe-glow {
animation: breathe 3s ease-in-out infinite;
}
@keyframes breathe {
0%, 100% {
box-shadow: 0 0 10px rgba(59, 130, 246, 0.3);
}
50% {
box-shadow: 0 0 20px rgba(59, 130, 246, 0.6);
}
}
New Item Indicator
Highlight new content.
CSS:
.new-item {
position: relative;
}
.new-item::before {
content: 'NEW';
position: absolute;
top: -8px;
right: -8px;
padding: 2px 6px;
background: #10b981;
color: white;
font-size: 10px;
font-weight: bold;
border-radius: 4px;
animation: new-bounce 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.new-item.fade-out::before {
animation: fade-out 300ms ease-out forwards;
}
@keyframes new-bounce {
0% { transform: scale(0) rotate(-12deg); }
100% { transform: scale(1) rotate(-12deg); }
}
Reduced Motion
For prefers-reduced-motion: reduce:
| Full Motion | Reduced Alternative |
|---|---|
| Pulsing | Static highlight color |
| Bouncing badge | Instant appearance |
| Ring pulse | Static border |
| Shimmer | Solid gray |
| Arrow bounce | Static arrow |
Implementation:
@media (prefers-reduced-motion: reduce) {
.pulse,
.badge.attention,
.ring-pulse::before,
.shimmer,
.arrow-hint,
.breathe-glow {
animation: none;
}
.ring-pulse::before {
opacity: 1;
transform: scale(1);
border-color: #3b82f6;
}
.shimmer {
background: #e0e0e0;
}
}
Accessibility Considerations
- Don't auto-play indefinitely pulsing animations
- Provide dismiss for persistent attention elements
- Limit frequency of attention-grabbing effects
- Color isn't enough - combine with shape/motion
- Respect focus - don't animate focused elements excessively
Cross-References
- See
accessibility/for WCAG requirements - See
glow-shadow/for glow effects - See
looping/for continuous animations - See
particles/for celebration effects
References
references/attention-patterns.md— UX attention patterns