CSS Animation Builder

CSS Animation Builder

Build CSS keyframe animations visually with timeline editor. Create custom @keyframes. Free online CSS animation generator with live preview

CSS animation that animates the wrong properties costs 60fps — animating `width` or `top` triggers layout on every frame; animating `transform: translateX` and `opacity` runs on the GPU compositor and stays smooth even on phones. This builder helps you author keyframes visually, previews the result, and warns when you are animating a non-composited property that will cause jank. Output is plain CSS `@keyframes` and `animation` shorthand, ready to paste.

The "cheap" vs "expensive" property list

  • GPU-cheap (compositor only) — `transform` (translate, scale, rotate, skew), `opacity`, `filter`. Animating these does not trigger layout or paint; runs at 60fps on weak phones.
  • CPU-expensive (triggers paint) — `color`, `background-color`, `border-color`, `box-shadow`. Paint is fast on small areas, slow on large ones.
  • CPU-very-expensive (triggers layout) — `width`, `height`, `top`, `left`, `margin`, `padding`, `font-size`. Every frame re-runs layout for the element AND its descendants. Often the source of "the animation drops frames on mobile".

The substitution rule: animate `transform: translateX(100px)` instead of `left: 100px`; animate `transform: scale(1.1)` instead of `width: 110%`. Same visual result, 10-100× cheaper.

Working example: a slide-in modal

Input

A modal that slides up from the bottom of the screen on open

Output

@keyframes slide-in-up {
  from {
    transform: translateY(100%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

.modal {
  animation: slide-in-up 250ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

Why this is cheap:
  - transform: animated on compositor, no layout.
  - opacity: animated on compositor, no paint.
  - 250ms duration: long enough to perceive, short enough to feel responsive.
  - cubic-bezier(0.16, 1, 0.3, 1): Apple-style ease-out — decelerates quickly
    to feel responsive while looking smooth.
  - forwards: keep final state after animation completes.

Compare to animating `bottom: -100% → bottom: 0`: triggers layout every frame, drops to 30fps on mid-range Android. Same effect visually, but the GPU-friendly version stays smooth even under load.

Easing curves and what they communicate

  • `linear` — constant speed. Feels robotic. Useful for progress indicators, loaders.
  • `ease-in` — starts slow, accelerates. Use for "leaving" animations — element gathers momentum as it exits.
  • `ease-out` — starts fast, decelerates. Use for "arriving" animations — element snaps into view, settles smoothly. Most-used easing for UI.
  • `ease-in-out` — slow at both ends. Smooth but slightly sleepy. Use for "moving from one state to another" without strong start/end emphasis.
  • Custom cubic-bezier — `cubic-bezier(0.16, 1, 0.3, 1)` is "soft-out" (apple-like). `cubic-bezier(0.34, 1.56, 0.64, 1)` is "back" (overshoots slightly).
  • Spring physics — newer CSS supports `spring()` with stiffness/damping. React Native and SwiftUI spring physics is the model; CSS catching up in 2025-26.

Animation timing rules of thumb

  • 0-100 ms — feels instant. Use for hover and active state changes.
  • 100-300 ms — feels responsive. Most UI transitions (modal open, panel slide, button feedback).
  • 300-500 ms — feels deliberate. "Page transition" or "story step" feel.
  • 500+ ms — feels slow. Use only when needed (loading transition, large layout reflow). Test with users; most people prefer faster.
  • Stagger — when animating multiple elements, offset their starts by 30-80ms. Otherwise they look like one block; staggered animation feels more refined.

Reduced motion

Some users get motion sickness from animation. The OS preference `prefers-reduced-motion` should disable or shorten non-essential animations. Always wrap large animations in `@media (prefers-reduced-motion: no-preference) { ... }` or use `@media (prefers-reduced-motion: reduce) { animation: none; }`.

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

When to reach for this tool

  • You are designing a new interaction (modal, tooltip, drawer) and want to tune the animation timing and easing visually.
  • You inherited animations that "feel janky" and want to identify which properties are causing the cost.
  • You are building a design system and want consistent animation tokens across all components.
  • You are explaining animation timing to a designer or stakeholder and want a live demo.

What this tool will not do

  • It will not animate JavaScript-controlled values (scroll position, complex interactions). For those, use Framer Motion, GSAP, or imperative JS.
  • It will not do parametric / spring physics fully. CSS support for spring() is partial in 2026; use a JS library for advanced spring animation.
  • It will not test on real devices. Animation that looks smooth in dev tools may drop frames on a 2018 budget Android. Test on real hardware.
  • It will not handle animation orchestration (timeline-based, multi-element coordination). For complex sequences, use a timeline tool (Framer, GSAP timeline).

Frequently asked questions

Should I use CSS animations or JavaScript animations?

CSS for declarative, looping, or one-shot animations on individual elements. JavaScript (Web Animations API, GSAP, Framer Motion) for complex orchestration, interrupting, scrubbing, or interactive animations driven by gestures. They share the same compositor backend; performance is comparable.

Why does my animation drop frames on mobile but not desktop?

Almost always animating an expensive property (layout-triggering). Open Chrome DevTools → Performance → record the animation → look for "Layout" purple bars in the frame breakdown. If you see them, replace the animated property with transform/opacity equivalent.

What is `will-change` and should I use it?

`will-change: transform` tells the browser to promote the element to its own compositor layer ahead of time. Helps avoid jank at animation start. Caveat: each compositor layer costs memory; overusing will-change tanks performance. Use sparingly, on elements you actually animate.

How long should a button hover animation be?

100-150 ms is the sweet spot. Less than 50 ms feels instant (no animation at all). More than 200 ms feels sluggish. For more pronounced effects (color change on accept), 200-250 ms is appropriate.

What is the difference between transition and animation?

`transition` animates between two states (default → hover, default → focus). One direction at a time; reverses automatically when state reverts. `animation` runs a keyframe sequence — can have multiple steps, can loop, can be paused. Use transition for state changes; animation for entrances, loaders, complex motion.

How do I animate height: auto?

Modern CSS: animate `grid-template-rows: 0fr → 1fr` (supported in modern browsers since 2024). Older approach: animate `max-height` from 0 to a large value; choppy near the end but compatible. Newer approach: animate `interpolate-size: allow-keywords` on parent. None of these are perfect; height animation remains the trickiest case in CSS.

Related tools

Last updated · E-Utils editorial team