Avatar Animation
Animated states on user avatar images or initials that communicate presence, status, recording state, and identity transitions.
Plain English
Static avatars are identity. Animated avatars are presence. The green dot on a LinkedIn profile does not just tell you someone is online — the pulsing version tells you they are active right now. A ring animation on an Instagram story tells you 'there is something new here, look'. A softly pulsing red ring on a face in a video call tells you you are live. These animations carry meaning that words would take three times as long to communicate. The design rules are tight: avatar animations must be small (never distract from content), purposeful (tied to real state), and immediately comprehensible (a pulse means active, a spin means loading, a ring means 'something is here').
Technical
Implement via CSS keyframes on a ring/border element layered over the avatar img. For the online pulse: a ::after pseudo-element at bottom-right, 10×10px, background: green, border-radius: 50%, with a scale+opacity pulse animation (1s ease-in-out infinite). For story rings: conic-gradient border on the avatar container, rotating via CSS animation. For skeleton→reveal: use a shimmer animation on a placeholder div, swap to the real img on load with a 200ms fade-in. For recording: red ring + pulsing scale (1.0→1.06→1.0, 1.5s). Always define all animations in motion-safe: {} in Tailwind or inside @media (prefers-reduced-motion: no-preference) {}.
Live Demo
Avatar animation states
All animations respect prefers-reduced-motion — the pulse and spin stop when reduced motion is set
Usage
✓ Good usage
A collaborative editing header showing team member avatars with: static grey for offline, subtle green pulse for online, animated red ring for "currently recording screen", skeleton shimmer while avatar URLs load — all communicating real-time state at a glance.
✗ Bad usage
An avatar that spins continuously to show it is "your account" or pulses green permanently regardless of actual online status — animation without information is noise.
Recommended values
- Online pulse indicator: 10–12px dot, 1.5–2 s pulse cycle
- Story ring: 2–3px gradient border, 3–4 s rotation (or static gradient for reduced-motion)
- Recording ring: 3px solid red border, 1.5 s scale pulse (1.0–1.06)
- Skeleton → reveal: shimmer 1.2 s, fade-in on load 200 ms ease-in
- Avatar size for status badge: badge ≤ 25% of avatar diameter
- Group avatars: max 4 visible, +N for overflow, 20–25% overlap
Common mistakes
- Animating the avatar image itself (scale, rotate) instead of a surrounding ring — disrupts face recognition.
- Status indicators that are too small (< 8px) or without a white border — invisible on coloured backgrounds.
- Running pulse animations without prefers-reduced-motion guards — a page full of pulsing avatars fails WCAG 2.2.2.
- No alt text or aria-label on avatar status — screen reader users cannot perceive animated visual state.
AI Prompt Example
Copy this into Claude, Cursor, Bolt, or v0.
Implement avatar status animation: wrap the avatar img in a relative-positioned container. Add a ::after pseudo-element (or a span) positioned bottom-right at 11×11px for status dot. Online: bg-green-500 with @keyframes pulse (scale 1→1.4→1, opacity 1→0.6→1, 2s infinite). Recording: replace dot with a 2px solid red ring on the avatar border, @keyframes recording-pulse (scale 1→1.05→1, 1.5s infinite). Skeleton: show a shimmer div (bg-gradient shimmer keyframe) until the img onLoad fires. All animations wrapped in @media (prefers-reduced-motion: no-preference).