Motion
Animation guidelines for Y3NKO interactions and transitions.
Principles
- Purposeful - Animations guide attention and provide feedback
- Subtle - Enhance, don’t distract
- Fast - Respect user time
- Accessible - Respect
prefers-reduced-motion
Duration Scale
| Speed | Duration | Usage |
|---|---|---|
| Fast | 150-200ms | Color changes, button hover |
| Medium | 300ms | Shadows, accordion, opacity |
| Slow | 500ms | Image scale transforms |
| Cinematic | 700ms | Carousel transitions, page transitions |
Transition Timing
Use ease for most transitions. For entrances, use ease-out. For exits, use ease-in.
// Standard transition
className="transition-colors duration-200 ease-in-out"
// Entrance animation
className="transition-all duration-300 ease-out"
// Exit animation
className="transition-all duration-200 ease-in"Common Patterns
Button Hover
<Button className="transition-colors duration-200">
{/* Background color change */}
</Button>Card Shadow Lift
<Card className="hover:shadow-lg transition-shadow duration-300">
{/* Shadow appears on hover */}
</Card>Card Image Scale
<div className="overflow-hidden">
<Image className="transition-transform duration-500 group-hover:scale-105" />
</div>Link Arrow Nudge
<Link className="group inline-flex items-center gap-2">
View Details
<ArrowRight className="transition-transform group-hover:translate-x-1" />
</Link>Favorite Heart Pop
<button className="transition-transform duration-200 hover:scale-110 active:scale-95">
<Heart />
</button>Accordion Expand
<AccordionContent className="transition-all duration-300 ease-out data-[state=open]:animate-accordion-down data-[state=closed]:animate-accordion-up">
{/* Content */}
</AccordionContent>Hover States
Color Change
/* Button background */
bg-[#CE1126] hover:bg-[#9E0D1D]
/* Text color */
text-[var(--night)] hover:text-[#CE1126]
/* Border color */
border-gray-300 hover:border-[#CE1126]Elevation Change
/* Shadow lift */
hover:shadow-lg
/* With transform */
hover:shadow-lg hover:-translate-y-1Scale Change
/* Subtle scale */
hover:scale-105
/* Image within container */
group-hover:scale-105Focus States
Focus animations should be instant for accessibility:
*:focus-visible {
outline: 2px solid var(--ghana-gold);
outline-offset: 2px;
/* No transition on focus for instant feedback */
}Loading States
Skeleton Pulse
<div className="animate-pulse bg-gray-100 rounded-lg h-48" />Button Loading
<Button disabled className="opacity-50">
<Loader2 className="animate-spin mr-2 h-4 w-4" />
Loading...
</Button>Spinner
<div className="animate-spin rounded-full h-8 w-8 border-2 border-gray-300 border-t-[#CE1126]" />Page Transitions
For page-level transitions, use CSS or Framer Motion:
// Simple fade
<main className="animate-in fade-in duration-300">
{/* Page content */}
</main>Carousel/Slider
<Carousel className="transition-transform duration-700 ease-out">
{/* Slides */}
</Carousel>Reduced Motion
Always respect user preferences:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}Or use Tailwind’s motion-safe:
<div className="motion-safe:transition-all motion-safe:duration-300">
{/* Only animates if user hasn't set reduced motion */}
</div>Animation Utilities
Add to globals.css:
.hover-lift {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.hover-lift:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-warm-lg);
}
.hover-glow {
transition: box-shadow 0.3s ease;
}
.hover-glow:hover {
box-shadow: var(--shadow-warm-glow);
}Tailwind Animation Classes
// Built-in
animate-spin // Loading spinner
animate-ping // Notification dot
animate-pulse // Skeleton loading
animate-bounce // Attention (use sparingly)
// Custom (via tailwind.config)
animate-fade-in
animate-slide-up
animate-accordion-down
animate-accordion-upDon’t Animate
Avoid animating:
- Layout shifts (CLS)
- Large images appearing
- Text content
- Critical UI elements users need immediately
Performance Tips
- Prefer
transformandopacity(GPU accelerated) - Avoid animating
width,height,margin,padding - Use
will-changesparingly - Keep animations under 300ms for interactions
- Test on low-end devices