CSS Animation Generator

Copy-paste CSS keyframe animations

Generates CSS @keyframes animation code for common effects: fade, slide, bounce, spin, pulse, and shake. Tune duration, delay, timing, and iteration, preview live, then copy ready-to-use CSS. No JavaScript required. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

What are CSS keyframes?

Keyframes define the steps of an animation using the @keyframes at-rule, listing how properties change at points from 0 to 100 percent. The animation property then attaches those keyframes to an element along with timing, delay, and iteration settings.

This generator produces ready-to-use CSS keyframe animations for the most common UI effects. Tune the timing, preview it live, and copy clean CSS you can drop straight into any project — no animation library or JavaScript needed.

How the generated CSS is structured

A CSS animation has two parts: a @keyframes block that describes the steps, and an animation declaration that attaches it to an element. This tool builds both.

For each effect it writes the appropriate keyframe steps. A fade animates opacity from 0 to 1; a slide combines opacity with a translateX or translateY offset that returns to 0; bounce and shake use multi-stop transform steps; spin rotates a full 360°; and pulse scales between 1 and 1.08. It then emits an animation-* set using your duration, delay, timing function, and iteration count, with animation-fill-mode: both so the element holds its start and end states.

The exported class is gera-animated, for example:

.gera-animated {
  animation-name: gera-fade;
  animation-duration: 800ms;
  animation-timing-function: ease;
  animation-iteration-count: 1;
  animation-fill-mode: both;
}

Effect guide and when to use each

EffectWhen to useRecommended timing
FadePage elements entering view, toasts, tooltips300–500ms, ease-out
SlideDrawers, sidebars, off-canvas panels250–400ms, ease-out
BounceSuccess confirmations, attention-drawing calls to action600–800ms, ease
SpinLoading spinners, processing indicatorsinfinite, linear
PulseNotification badges, heartbeat loadersinfinite, ease-in-out
ShakeError states, failed form validation400–600ms, ease

Worked example: entrance card animation

You want a card to slide up and fade in when a page loads. Choose slide, direction up, duration 400ms, delay 100ms, timing ease-out, iteration 1:

@keyframes gera-slide-up {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.gera-animated {
  animation-name: gera-slide-up;
  animation-duration: 400ms;
  animation-delay: 100ms;
  animation-timing-function: ease-out;
  animation-iteration-count: 1;
  animation-fill-mode: both;
}

Apply .gera-animated to each card. The animation-fill-mode: both keeps the card invisible during the 100ms delay, then holds the final visible state after the animation finishes.

Timing function cheat sheet

The timing function controls how the animation progresses over its duration:

  • ease — starts slow, speeds up, ends slow. Good all-rounder.
  • ease-out — starts fast, decelerates to a stop. Best for elements entering the screen; feels natural.
  • ease-in — starts slow, accelerates. Good for elements leaving the screen.
  • linear — constant speed. Correct for spinners and anything that should feel mechanical.
  • cubic-bezier — custom curve. Use an overshoot value (for example cubic-bezier(0.34, 1.56, 0.64, 1)) to add a springy bounce past the end state.

Performance: why these effects only touch transform and opacity

Every effect this generator emits animates only transform and opacity — deliberately. Browsers can hand those two properties to the compositor thread and animate them on the GPU without recalculating layout or repainting, so the animation stays smooth even while the main thread is busy. Animating width, height, top/left, or margin instead forces layout on every frame and is the classic cause of janky entrance animations on mid-range phones. If you customise the generated keyframes, stay inside transform/opacity (and filter where needed) to keep the fast path.

Two related gotchas:

  • Existing transforms get overwritten. The keyframes set the whole transform property, so an element already positioned with transform: translateX(-50%) will jump when the animation starts. Combine the values inside the keyframes (e.g. translate(-50%, 20px)), or animate a wrapper element instead.
  • display: none elements don’t animate in. Switching from display:none to block and adding the class in the same frame skips the animation in some browsers. Toggle visibility first, force a reflow (or use requestAnimationFrame), then add the class — or keep the element rendered and animate opacity.

Replaying and staggering without a library

  • Replay on demand: removing and re-adding the class only works if the browser processes a style flush in between. The reliable pattern is el.classList.remove('gera-animated'); void el.offsetWidth; el.classList.add('gera-animated'); — the offsetWidth read forces the reflow. Alternatively, listen for animationend and reset there.
  • Staggered lists: give every item the same class and offset the delays with a custom property: set style="--i: 3" per item and animation-delay: calc(var(--i) * 80ms) in your stylesheet. An 80–120ms step reads as a deliberate cascade; longer gaps feel sluggish.
  • Respect reduced motion by default: rather than opting motion out, gate it in — declare the animation-* properties inside @media (prefers-reduced-motion: no-preference) so users who have asked the OS for less motion simply see the element in its final state. Vestibular disorders make large slides and shakes genuinely unpleasant; fades are the safest effect to leave enabled.

Tips and notes

For entrance effects (fade, slide) keep the iteration count at 1 and use an ease-out timing function so motion settles naturally. For loaders use spin or pulse with infinite and linear. The cubic-bezier overshoot option adds a springy feel to slide and bounce. Respect users who prefer reduced motion by wrapping the class in a @media (prefers-reduced-motion: no-preference) query in your own stylesheet.

Sources and references

Maintained by the Gera Tools editorial team. The exported CSS is pure @keyframes + a class with no JavaScript dependency; wrap it in a reduced-motion query for accessibility. Last reviewed 2026-07-02.