Transitions & Animation
Overview
Transition and animation utilities help you create smooth visual changes and motion effects. These utilities control which properties animate, how long animations take, and what easing functions to use.
Why Use Transition & Animation Utilities?
Transition and animation utilities help you:
- Create smooth interactions: Add polish with animated hover and focus states
- Control timing: Define consistent animation durations across your application
- Apply easing functions: Use predefined timing functions for natural motion
- Improve user experience: Guide attention with purposeful animations
useTransitionPropertyUtility
The useTransitionPropertyUtility() function creates utility classes for specifying which properties should animate.
import { styleframe } from "styleframe";
import { useTransitionPropertyUtility } from "@styleframe/theme";
const s = styleframe();
useTransitionPropertyUtility(s, {
none: 'none',
all: 'all',
default: 'color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter',
colors: 'color, background-color, border-color, text-decoration-color, fill, stroke',
opacity: 'opacity',
shadow: 'box-shadow',
transform: 'transform',
});
export default s;
._transition\:none {
transition-property: none;
}
._transition\:all {
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
._transition {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
._transition\:colors {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
._transition\:opacity {
transition-property: opacity;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
._transition\:shadow {
transition-property: box-shadow;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
._transition\:transform {
transition-property: transform;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
<button class="_transition:colors">Animated color changes</button>
<div class="_transition:transform">Animated transform</div>
<div class="_transition">All common properties animate</div>
useTransitionDurationUtility
The useTransitionDurationUtility() function creates utility classes for setting animation duration.
import { styleframe } from "styleframe";
import { useTransitionDurationUtility } from "@styleframe/theme";
const s = styleframe();
useTransitionDurationUtility(s, {
'0': '0s',
'75': '75ms',
'100': '100ms',
'150': '150ms',
'200': '200ms',
'300': '300ms',
'500': '500ms',
'700': '700ms',
'1000': '1000ms',
});
export default s;
._transition-duration\:0 { transition-duration: 0s; }
._transition-duration\:75 { transition-duration: 75ms; }
._transition-duration\:100 { transition-duration: 100ms; }
._transition-duration\:150 { transition-duration: 150ms; }
._transition-duration\:200 { transition-duration: 200ms; }
._transition-duration\:300 { transition-duration: 300ms; }
._transition-duration\:500 { transition-duration: 500ms; }
._transition-duration\:700 { transition-duration: 700ms; }
._transition-duration\:1000 { transition-duration: 1000ms; }
<button class="_transition:colors _transition-duration:200">Fast transition</button>
<div class="_transition:opacity _transition-duration:500">Slower fade</div>
useTransitionTimingFunctionUtility
The useTransitionTimingFunctionUtility() function creates utility classes for setting easing functions.
import { styleframe } from "styleframe";
import { useTransitionTimingFunctionUtility } from "@styleframe/theme";
const s = styleframe();
useTransitionTimingFunctionUtility(s, {
linear: 'linear',
in: 'cubic-bezier(0.4, 0, 1, 1)',
out: 'cubic-bezier(0, 0, 0.2, 1)',
'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
});
export default s;
._transition-timing\:linear { transition-timing-function: linear; }
._transition-timing\:in { transition-timing-function: cubic-bezier(0.4, 0, 1, 1); }
._transition-timing\:out { transition-timing-function: cubic-bezier(0, 0, 0.2, 1); }
._transition-timing\:in-out { transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); }
<div class="_transition:transform _transition-timing:out">Ease out</div>
<div class="_transition:opacity _transition-timing:in-out">Smooth in and out</div>
Easing Functions
| Value | Description |
|---|---|
linear | Constant speed throughout |
in | Starts slow, accelerates (ease-in) |
out | Starts fast, decelerates (ease-out) |
in-out | Slow start and end (ease-in-out) |
useTransitionDelayUtility
The useTransitionDelayUtility() function creates utility classes for delaying transitions.
import { styleframe } from "styleframe";
import { useTransitionDelayUtility } from "@styleframe/theme";
const s = styleframe();
useTransitionDelayUtility(s, {
'0': '0s',
'75': '75ms',
'100': '100ms',
'150': '150ms',
'200': '200ms',
'300': '300ms',
'500': '500ms',
'700': '700ms',
'1000': '1000ms',
});
export default s;
._transition-delay\:0 { transition-delay: 0s; }
._transition-delay\:75 { transition-delay: 75ms; }
._transition-delay\:100 { transition-delay: 100ms; }
._transition-delay\:150 { transition-delay: 150ms; }
._transition-delay\:200 { transition-delay: 200ms; }
._transition-delay\:300 { transition-delay: 300ms; }
._transition-delay\:500 { transition-delay: 500ms; }
/* ... more values */
<div class="_transition:colors _transition-delay:150">Delayed color transition</div>
<div class="_transition:transform _transition-delay:300">Delayed transform</div>
useAnimationUtility
The useAnimationUtility() function creates utility classes for applying CSS animations.
import { styleframe } from "styleframe";
import { useAnimationUtility } from "@styleframe/theme";
const s = styleframe();
const { keyframes } = s;
// Define keyframes
const spin = keyframes('spin', {
'from': { transform: 'rotate(0deg)' },
'to': { transform: 'rotate(360deg)' },
});
const ping = keyframes('ping', {
'75%, 100%': { transform: 'scale(2)', opacity: '0' },
});
const pulse = keyframes('pulse', {
'0%, 100%': { opacity: '1' },
'50%': { opacity: '.5' },
});
const bounce = keyframes('bounce', {
'0%, 100%': { transform: 'translateY(-25%)', animationTimingFunction: 'cubic-bezier(0.8, 0, 1, 1)' },
'50%': { transform: 'translateY(0)', animationTimingFunction: 'cubic-bezier(0, 0, 0.2, 1)' },
});
useAnimationUtility(s, {
none: 'none',
spin: `${spin.name} 1s linear infinite`,
ping: `${ping.name} 1s cubic-bezier(0, 0, 0.2, 1) infinite`,
pulse: `${pulse.name} 2s cubic-bezier(0.4, 0, 0.6, 1) infinite`,
bounce: `${bounce.name} 1s infinite`,
});
export default s;
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes ping {
75%, 100% { transform: scale(2); opacity: 0; }
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: .5; }
}
@keyframes bounce {
0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); }
50% { transform: translateY(0); animation-timing-function: cubic-bezier(0, 0, 0.2, 1); }
}
._animation\:none { animation: none; }
._animation\:spin { animation: spin 1s linear infinite; }
._animation\:ping { animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; }
._animation\:pulse { animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; }
._animation\:bounce { animation: bounce 1s infinite; }
<svg class="_animation:spin"><!-- Loading spinner --></svg>
<span class="_animation:ping"><!-- Notification dot --></span>
<div class="_animation:pulse"><!-- Skeleton loader --></div>
<div class="_animation:bounce"><!-- Bouncing element --></div>
Examples
Hover Transition
import { styleframe } from "styleframe";
import { useTransitionPropertyUtility, useTransitionDurationUtility } from "@styleframe/theme";
import { useBackgroundColorUtility } from "@styleframe/theme";
const s = styleframe();
const { modifier } = s;
const hover = modifier('hover', ({ declarations }) => ({
'&:hover': declarations,
}));
useTransitionPropertyUtility(s, {
colors: 'color, background-color, border-color',
});
useTransitionDurationUtility(s, {
'200': '200ms',
});
useBackgroundColorUtility(s, {
gray: '#f3f4f6',
primary: '#006cff',
});
useBackgroundColorUtility(s, { primary: '#006cff' }, [hover]);
export default s;
._transition\:colors {
transition-property: color, background-color, border-color;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
._transition-duration\:200 { transition-duration: 200ms; }
._bg\:gray { background-color: #f3f4f6; }
._bg\:primary { background-color: #006cff; }
._hover\:bg\:primary:hover { background-color: #006cff; }
Usage in HTML:
<button class="_bg:gray _hover:bg:primary _transition:colors _transition-duration:200">
Hover me
</button>
Loading Spinner
import { styleframe } from "styleframe";
import { useAnimationUtility } from "@styleframe/theme";
const s = styleframe();
const { keyframes } = s;
const spin = keyframes('spin', {
'from': { transform: 'rotate(0deg)' },
'to': { transform: 'rotate(360deg)' },
});
useAnimationUtility(s, {
spin: `${spin.name} 1s linear infinite`,
});
export default s;
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
._animation\:spin { animation: spin 1s linear infinite; }
Usage in HTML:
<svg class="_animation:spin" width="24" height="24">
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none" />
</svg>
Best Practices
- Use purposeful animation: Animations should enhance UX, not distract
- Respect reduced motion: Consider users who prefer reduced motion
- Keep durations short: Most UI transitions should be 150-300ms
- Use appropriate easing: Ease-out for entering, ease-in for leaving
- Avoid animating layout: Prefer transform and opacity for performance
- Be consistent: Use the same timing across similar interactions
FAQ
prefers-reduced-motion media query to disable or reduce animations. Consider creating a modifier that respects this preference, or set animation: none and transition: none globally for these users.