CSS Animation Pattern
Create performant CSS animations with Tailwind transitions, keyframe utilities, and motion-safe considerations
When to Use
- Adding hover/focus transitions to interactive elements
- Animating element entrance (fade in, slide up)
- Building loading spinners and skeleton screens
- Creating micro-interactions that improve UX
Instructions
- Use
transition-*utilities for property transitions (hover, focus, state changes). - Use
animate-*utilities for keyframe animations (continuous motion, entrance effects). - Only animate
transformandopacityfor 60fps performance — avoid animatingwidth,height,margin, ortop. - Respect user preferences: use
motion-safe:prefix so animations only play when the user has not enabled "reduce motion". - Keep animations short (150-300ms for transitions, 500-1000ms for entrances).
- Define custom keyframes in
tailwind.config.tsfor project-specific animations.
// Transitions — state-based property changes
function Button({ children }: { children: React.ReactNode }) {
return (
<button className="
bg-blue-600 text-white px-4 py-2 rounded-md
transition-all duration-200 ease-in-out
hover:bg-blue-700 hover:shadow-lg hover:-translate-y-0.5
active:translate-y-0 active:shadow-md
focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2
">
{children}
</button>
);
}
// Entrance animation with motion-safe
function FadeIn({ children }: { children: React.ReactNode }) {
return (
<div className="motion-safe:animate-fade-in motion-reduce:opacity-100">
{children}
</div>
);
}
// Built-in Tailwind animations
<div className="animate-spin h-8 w-8 border-4 border-blue-600 border-t-transparent rounded-full" />
<div className="animate-pulse bg-gray-200 h-4 rounded" />
<div className="animate-bounce text-2xl">👇</div>
// tailwind.config.ts — custom animations
const config: Config = {
theme: {
extend: {
keyframes: {
'fade-in': {
'0%': { opacity: '0', transform: 'translateY(10px)' },
'100%': { opacity: '1', transform: 'translateY(0)' },
},
'slide-in-right': {
'0%': { transform: 'translateX(100%)' },
'100%': { transform: 'translateX(0)' },
},
'scale-in': {
'0%': { opacity: '0', transform: 'scale(0.95)' },
'100%': { opacity: '1', transform: 'scale(1)' },
},
},
animation: {
'fade-in': 'fade-in 0.5s ease-out forwards',
'slide-in-right': 'slide-in-right 0.3s ease-out',
'scale-in': 'scale-in 0.2s ease-out',
},
},
},
};
Details
Performance-safe properties: The browser can animate transform and opacity on the GPU (compositor layer) without triggering layout recalculation. Animating other properties causes reflow:
| Safe (GPU) | Unsafe (reflow) |
|---|---|
transform (translate, scale, rotate) |
width, height |
opacity |
margin, padding |
filter |
top, left, right, bottom |
border-width, font-size |
Transition utilities:
transition— all properties (color, background, border, shadow, transform, opacity)transition-colors— only color-related propertiestransition-transform— only transformtransition-opacity— only opacityduration-*— 75, 100, 150, 200, 300, 500, 700, 1000ease-*— linear, in, out, in-out
Motion accessibility: Always use motion-safe: for decorative animations. Users with vestibular disorders can enable "reduce motion" in their OS settings:
<div className="motion-safe:animate-fade-in motion-reduce:opacity-100">
Content appears instantly for motion-sensitive users
</div>
Staggered animations (with custom properties):
{
items.map((item, i) => (
<div
key={item.id}
className="motion-safe:animate-fade-in"
style={{ animationDelay: `${i * 100}ms` }}
>
{item.name}
</div>
));
}
Source
https://tailwindcss.com/docs/animation
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.