API Essentials

Keyframes

Styleframe keyframes enable you to create smooth CSS animations with type-safe property definitions. Build engaging motion effects that enhance user experience across your application.

Overview

Keyframes in Styleframe provide a powerful way to create CSS animations with full type safety and auto-complete. You can define animation sequences that smoothly transition between different states, creating engaging motion effects while maintaining the benefits of Styleframe's TypeScript support.

Why use keyframes?

Keyframes help you:

  • Create smooth animations: Build fluid motion effects that enhance user experience and guide attention.
  • Maintain design consistency: Use variables and tokens to ensure consistent timing and easing across animations.
  • Write maintainable code: Leverage type safety and organized structure to prevent common animation mistakes.
  • Generate optimized output: Let Styleframe handle the generation of clean, efficient CSS animations.

Defining Keyframes

You define keyframes using the keyframes() function from your styleframe instance:

import { styleframe, css } from 'styleframe';

const s = styleframe();
const { keyframes, selector, ref } = s;

const fadeInKeyframes = keyframes('fade-in', {
    '0%': {
        opacity: 0,
        transform: 'translateY(20px)',
    },
    '100%': {
        opacity: 1,
        transform: 'translateY(0)',
    },
});

selector('.animated-element', {
    animation: css`${ref(fadeInKeyframes)} 0.3s ease-out`,
});

export default s;

Each keyframe takes an animation name and a keyframes object with percentage-based stops defining the animation sequence.

Pro tip: Use descriptive animation names that clearly indicate the motion effect. This makes your animations more maintainable and reusable.

Using Variables with Keyframes

For better maintainability and consistency, combine keyframes with variables:

import { styleframe, css } from 'styleframe';

const s = styleframe();
const { variable, ref, keyframes, selector } = s;

const animationDurationFast = variable('animation-duration--fast', '0.2s');
const animationDurationNormal = variable('animation-duration--normal', '0.3s');
const transformTranslateUp = variable('transform--translate-up', 'translateY(-10px)');
const colorPrimary = variable('color--primary', '#006cff');
const colorPrimaryHover = variable('color--primary-hover', '#0056cc');

const buttonHoverKeyframes = keyframes('button-hover', {
    '0%': {
        transform: 'translateY(0)',
        backgroundColor: ref(colorPrimary),
    },
    '100%': {
        transform: ref(transformTranslateUp),
        backgroundColor: ref(colorPrimaryHover),
    },
});

selector('.interactive-button', {
    backgroundColor: ref(colorPrimary),
    transition: css`all ${ref(animationDurationNormal)} ease`,

    '&:hover': {
        animation: css`${ref(buttonHoverKeyframes)} ${ref(animationDurationFast)} ease-out`,
    },
});

export default s;

Responsive Keyframes

You can create different keyframe animations for different screen sizes using media queries:

import { styleframe, css } from 'styleframe';

const s = styleframe();
const { keyframes, selector, media, ref } = s;

const slideInMobileKeyframes = keyframes('slide-in-mobile', {
    '0%': {
        transform: 'translateX(-100%)',
        opacity: 0,
    },
    '100%': {
        transform: 'translateX(0)',
        opacity: 1,
    },
});

const slideInDesktopKeyframes = keyframes('slide-in-desktop', {
    '0%': {
        transform: 'translateY(-50px) scale(0.9)',
        opacity: 0,
    },
    '100%': {
        transform: 'translateY(0) scale(1)',
        opacity: 1,
    },
});

selector('.modal', {
    animation: css`${ref(slideInMobileKeyframes)} 0.3s ease-out`,
});

media('(min-width: 768px)', ({ selector }) => {
    selector('.modal', {
        animation: css`${ref(slideInDesktopKeyframes)} 0.4s ease-out`,
    });
});

export default s;

Examples

Animation Utilities

Create reusable animation patterns by combining keyframes with utility selectors:

import { styleframe, css } from 'styleframe';

const s = styleframe();
const { keyframes, selector, ref } = s;

const pulseKeyframes = keyframes('pulse', {
    '0%': {
        transform: 'scale(1)',
        opacity: 1,
    },
    '50%': {
        transform: 'scale(1.05)',
        opacity: 0.8,
    },
    '100%': {
        transform: 'scale(1)',
        opacity: 1,
    },
});

const spinKeyframes = keyframes('spin', {
    '0%': {
        transform: 'rotate(0deg)',
    },
    '100%': {
        transform: 'rotate(360deg)',
    },
});

const shakeKeyframes = keyframes('shake', {
    '0%, 100%': {
        transform: 'translateX(0)',
    },
    '10%, 30%, 50%, 70%, 90%': {
        transform: 'translateX(-10px)',
    },
    '20%, 40%, 60%, 80%': {
        transform: 'translateX(10px)',
    },
});

selector('.animate-pulse', {
    animation: css`${ref(pulseKeyframes)} 2s cubic-bezier(0.4, 0, 0.6, 1) infinite`,
});

selector('.animate-spin', {
    animation: css`${ref(spinKeyframes)} 1s linear infinite`,
});

selector('.animate-shake', {
    animation: css`${ref(shakeKeyframes)} 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97)`,
});

export default s;

Animation States and Controls

You can create animations that respond to different states or user interactions:

import { styleframe, css } from 'styleframe';

const s = styleframe();
const { keyframes, selector, ref } = s;

const expandWidthKeyframes = keyframes('expand-width', {
    '0%': {
        width: '0%',
    },
    '100%': {
        width: '100%',
    },
});

selector('.progress-bar', {
    width: '0%',
    height: '4px',
    backgroundColor: '#006cff',
    transition: 'width 0.3s ease',

    '&.active': {
        animation: css`${ref(expandWidthKeyframes)} 2s ease-out forwards`,
    },
});

export default s;
import { styleframe, css } from 'styleframe';

const s = styleframe();
const { keyframes, selector, ref } = s;

const fadeInUpKeyframes = keyframes('fade-in-up', {
    '0%': {
        opacity: 0,
        transform: 'translateY(30px)',
    },
    '100%': {
        opacity: 1,
        transform: 'translateY(0)',
    },
});

selector('.notification', {
    opacity: 0,
    transform: 'translateY(30px)',

    '&.show': {
        animation: css`${ref(fadeInUpKeyframes)} 0.4s ease-out forwards`,
    },
    
    '&.hide': {
        animation: css`${ref(fadeInUpKeyframes)} 0.4s ease-out reverse`,
    },
});

export default s;

Complex Keyframe Sequences

You can create sophisticated animations with multiple keyframe stops:

import { styleframe, css } from 'styleframe';

const s = styleframe();
const { keyframes, selector, ref } = s;

const bounceKeyframes = keyframes('bounce', {
    '0%': {
        transform: 'translateY(0)',
        animationTimingFunction: 'ease-out',
    },
    '25%': {
        transform: 'translateY(-20px)',
        animationTimingFunction: 'ease-in',
    },
    '50%': {
        transform: 'translateY(0)',
        animationTimingFunction: 'ease-out',
    },
    '75%': {
        transform: 'translateY(-10px)',
        animationTimingFunction: 'ease-in',
    },
    '100%': {
        transform: 'translateY(0)',
        animationTimingFunction: 'ease-out',
    },
});

selector('.bouncing-button', {
    animation: css`${ref(bounceKeyframes)} 0.6s infinite`,
});

export default s;

Best Practices

  • Use meaningful animation names that describe the motion effect or purpose.
  • Define animation variables for durations, easing functions, and common transform values.
  • Consider performance by animating only transform and opacity properties when possible.
  • Respect user preferences by providing reduced motion alternatives for users who prefer less animation.
  • Keep animations purposeful and avoid overusing motion effects that might distract from content.

FAQ