Create keyframe animations that are scoped and hashed to avoid naming conflicts. The animation name is automatically generated at build time.
Function Signature
function keyframes(
strings: TemplateStringsArray,
...interpolations: never[]
): string;
Parameters
strings
TemplateStringsArray
required
Template literal strings containing keyframe rules
No interpolations allowed - keyframes must be static
Returns
A scoped animation name (e.g., "ss-abc123")
Usage
Basic Animation
Create a simple spinning animation:
import { keyframes, styled } from '@alex.radulescu/styled-static';
const spin = keyframes`
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
`;
const Spinner = styled.div`
width: 24px;
height: 24px;
border: 2px solid #3b82f6;
border-top-color: transparent;
border-radius: 50%;
animation: ${spin} 1s linear infinite;
`;
Complex Animations
Use percentage-based keyframes for more complex animations:
const pulse = keyframes`
0%, 100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.5;
transform: scale(0.95);
}
`;
const PulsingDot = styled.div`
width: 8px;
height: 8px;
background: #10b981;
border-radius: 50%;
animation: ${pulse} 2s ease-in-out infinite;
`;
Multiple Animations
Combine multiple keyframe animations:
const fadeIn = keyframes`
from { opacity: 0; }
to { opacity: 1; }
`;
const slideUp = keyframes`
from { transform: translateY(20px); }
to { transform: translateY(0); }
`;
const Modal = styled.div`
animation:
${fadeIn} 0.3s ease-out,
${slideUp} 0.3s ease-out;
`;
Loading Indicators
Create loading animations with multiple steps:
const bounce = keyframes`
0%, 80%, 100% {
transform: scale(0);
opacity: 0.5;
}
40% {
transform: scale(1);
opacity: 1;
}
`;
const LoadingDot = styled.div`
width: 12px;
height: 12px;
background: #3b82f6;
border-radius: 50%;
animation: ${bounce} 1.4s ease-in-out infinite;
&:nth-child(1) { animation-delay: -0.32s; }
&:nth-child(2) { animation-delay: -0.16s; }
`;
How It Works
Keyframes are extracted and hashed at build time:
// What you write:
const spin = keyframes`
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
`;
const Spinner = styled.div`
animation: ${spin} 1s linear infinite;
`;
// What gets generated:
const spin = "ss-abc123";
const Spinner = /* ... */;
// In CSS output:
// @keyframes ss-abc123 {
// from { transform: rotate(0deg); }
// to { transform: rotate(360deg); }
// }
// .ss-xyz789 { animation: ss-abc123 1s linear infinite; }
Automatic Scoping
Animation names are automatically hashed to avoid conflicts:
// Component A
const spin = keyframes`...`; // → "ss-abc123"
// Component B (different file)
const spin = keyframes`...`; // → "ss-def456"
// No naming conflicts!
Animation Properties
Use keyframes with any animation properties:
const wiggle = keyframes`
0%, 100% { transform: rotate(-3deg); }
50% { type: rotate(3deg); }
`;
const Button = styled.button`
/* Long form */
animation-name: ${wiggle};
animation-duration: 0.5s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
/* Shorthand */
animation: ${wiggle} 0.5s ease-in-out infinite;
`;
See Also