AI CSS Animations

Guides · · Maxwell Prehoda

14 CSS Keyframes Examples by Pattern, Each Running Live With the Code to Copy

A CSS keyframe animation is two parts: an `@keyframes` rule that names the states (`from`, `to` or any percentages in between) and an `animation` declaration that plays it with a duration, a curve, a repeat count and a fill mode. Every pattern below is a different way of combining those two parts, from a two-line fade to a cube that rolls through four faces.

We grouped the examples by pattern rather than by effect, so you learn the technique, not just the look. Each pattern is tied to the reference or library that made it standard, MDN, Animate.css, Animista, Tailwind, Josh Comeau, David DeSandro and Bramus, and each one plays live from our Keyframe Animations directory with the exact CSS one click away.

1. MDN: percentages for multi-step motion: Best for like buttons, live badges and anything with a rhythm

Platform: CSS, every browser (MDN reference)

Live from our directory: Heartbeat. Copy the HTML and CSS →

MDN's guide to CSS animations sets out the basics every example here relies on. `0%` is the first moment of the sequence and `100%` the last, with `from` and `to` as aliases, and both are optional: leave one out and the browser uses the element's computed values for that end. Anything in between is just more percentages.

That is how you get rhythm. A heartbeat is not two states but five: rest, a small beat, a dip, a bigger beat, rest again. Listing several percentages on one line (`50%, 100%`) holds a pose, which is how you build a pause into a loop without JavaScript.

Our Heartbeat below beats lub-dub at 10 and 30 percent of a 1.5 s cycle, then rests from 50 to 100 percent. Each step has its own timing function so every beat rises fast and eases back.

Watch out for: A timing function set inside a keyframe applies until the next keyframe that sets the same property, so one on `100%` is never used. Put curves on the keyframe where each leg starts.

2. Animate.css: entrances as drop-in classes: Best for adding a known entrance to a landing page in minutes

Platform: Animate.css 4.1.1, Hippocratic License

Back
Live from our directory: Back In Up. Copy the HTML and CSS →

Animate.css is the library that made keyframe entrances a class name. Add `animate__animated` plus an effect class such as a back, fade, bounce or zoom entrance, and the element plays it. Version 4 moved timing into custom properties, `--animate-duration`, `--animate-delay` and `--animate-repeat`, so you can retime one element or the whole site without touching the keyframes. It also respects `prefers-reduced-motion`, and its docs ask you not to switch that off.

The library groups effects into attention seekers, back, bouncing, fading, flippers, lightspeed, rotating, specials, zooming and sliding. That taxonomy is a good mental model even if you never install it: is this animation an entrance, an exit or a call for attention?

Our Back In Up below is our own pure-CSS take on the back-entrance pattern: it rises at 70 percent size and partly see-through, then grows to full size on an ease-out back curve, so it reads as arriving from behind.

Watch out for: Shipping the full library for one or two effects adds CSS you do not use. Copy the keyframes you need, or use a build step that keeps only them.

3. MDN: exits and the animationend event: Best for dismissing notifications and removing elements

Platform: CSS plus a few lines of JavaScript

Hinge
Live from our directory: Hinge. Copy the HTML and CSS →

An exit animation has a job entrances do not: something has to remove the element when it is done. MDN documents the three animation events, `animationstart`, `animationiteration` and `animationend`, and notes that after the final iteration you get `animationend` instead of another `animationiteration`. Listen for it, then remove or hide the node.

Keep the final state with `animation-fill-mode: forwards` or `both` so the element does not flash back to visible in the gap between the animation ending and your code running.

Our Hinge below is a pure-CSS version of the classic hinge exit made famous by Animate.css: it swings from its top-left corner, sways twice, then drops and fades over 2 s. A `transform-origin` of `0 0` does all the pivoting.

Watch out for: If a reduced-motion rule sets `animation: none`, `animationend` never fires and your element never leaves. Use a near-zero duration instead so the event still fires.

4. Animista by Ana Travas: tune it, then copy the keyframes: Best for trying variations before committing to one

Platform: Free web app, generated CSS under the FreeBSD license

Puff
Live from our directory: Puff In. Copy the HTML and CSS →

Animista is a playground of pre-made CSS animations grouped by what they are for: box, button, text, letter, image, card, cube and more. Pick one, then adjust duration, timing function, delay, iteration count, direction and fill mode and watch the result update. When it looks right, generate the class or copy just the keyframes, minified and autoprefixed if you like.

The site says everything it generates is free for personal and commercial use. Its real value is the controls: you learn what each `animation-*` property does by moving it and seeing the change.

Our Puff In below is our pure-CSS take on the puff-in idea: it starts oversized, blurred and transparent and collapses into focus on an ease-in curve, so it lands with a small thump.

Watch out for: Animista's defaults are tuned to be seen in a demo. Shorten durations before shipping, and be careful with effects that animate `filter`, which costs more than transform and opacity.

5. Tailwind animate-ping: a pseudo-element that pulses out: Best for live dots, unread badges and new-feature markers

Platform: Tailwind CSS v4 utility

Ping
Live from our directory: Ping. Copy the HTML and CSS →

Tailwind's four built-in animations are a compact lesson in keyframes. `animate-ping` runs a 1 s loop on `cubic-bezier(0, 0, 0.2, 1)` with a single keyframe at `75%, 100%` that scales to 2 and fades to 0, so the shape swells and vanishes, then snaps back and starts again. Tailwind's docs pair it with the `motion-safe:` variant so it only runs for people who have not asked for less motion.

The pattern worth copying is putting the ping on a copy of the shape, not the element itself. The badge stays put and readable while a ghost ring expands behind it.

Our Ping below does exactly that with a `::before` behind the content, so the element never moves.

Watch out for: An endless ping is attention-seeking by design. Use it for one thing that is genuinely new or live, and stop it once the person has seen it.

6. Tailwind animate-bounce: a curve on each leg: Best for scroll-down hints and playful idle loops

Platform: Tailwind CSS v4 utility

Bounce
Live from our directory: Bounce Up and Down. Copy the HTML and CSS →

`animate-bounce` shows the most underused keyframe technique: different easing on different legs. Its keyframes are just two states, `0%, 100%` at `translateY(-25%)` with `cubic-bezier(0.8, 0, 1, 1)`, and `50%` at rest with `cubic-bezier(0, 0, 0.2, 1)`. The drop accelerates like gravity, the climb decelerates, and a two-state animation reads as physics.

You can define your own the same way in Tailwind v4 by declaring a `--animate-*` variable and its `@keyframes` inside `@theme`, which then becomes a utility class.

Our Bounce Up and Down below uses the same curves as Tailwind's animate-bounce: an ease-in drop and an ease-out climb, once a second.

Watch out for: A constantly bouncing arrow on a hero section is one of the most common sources of motion people find irritating. Bounce a few times, then stop.

7. Josh W. Comeau: fill modes and alternate: Best for fixing flashes and snap-backs at start and end

Platform: Interactive guide, joshwcomeau.com

Fade
Live from our directory: Fade Out. Copy the HTML and CSS →

Josh Comeau calls fill modes probably the most confusing part of keyframe animations, and his interactive guide explains them better than anyone. Without a fill mode, an element shows its normal styles before a delayed animation starts and snaps back to them when it ends. `forwards` keeps the last keyframe, `backwards` applies the first keyframe during the delay, and `both` does both, which is what most one-shot animations want.

The same guide covers `animation-direction: alternate`, which plays forward then backward so a grow-and-shrink loop needs only one direction of keyframes (and half the duration for the same feel), and using CSS variables inside keyframes so one rule serves many elements.

Our Fade Out below is the plain opacity exit on an ease-in curve with fill mode `both`, so it stays gone after it finishes instead of popping back.

Watch out for: A forwards fill keeps applying the final keyframe's values, which overrides later style changes to the same properties. If a hover stops working after an entrance, the fill mode is the usual cause.

8. MDN: steps() for frame-by-frame text: Best for typewriter headlines and terminal heroes

Platform: CSS, every browser (MDN reference)

Hello, world.
Live from our directory: Typewriter Effect. Copy the HTML and CSS →

Not every keyframe animation should be smooth. MDN describes `steps()` as a stair-shaped easing: an integer number of intervals and an optional jump keyword. Applied to a width measured in `ch`, it reveals monospace text one character at a time, the classic pure-CSS typewriter.

The typewriter is also a good example of two animations on one element: one stepped animation types the text, and a separate looping one blinks the caret. MDN's guide notes that every animation longhand accepts comma-separated lists, one value per animation.

Our Typewriter Effect below steps its width one character per frame using `ch` units. Set the step count to your text's length and it types exactly that many characters.

Watch out for: Animating width is layout work, and the trick only lines up in monospace fonts. For long or proportional text, reveal characters with a clip-path or per-letter spans instead.

9. David DeSandro: 3D keyframes on a cube: Best for rotating words, stats or logos in a hero

Platform: Intro to CSS 3D Transforms, free guide

OneTwoThreeFour
Live from our directory: 3D Cube Rotate. Copy the HTML and CSS →

David DeSandro's "Intro to CSS 3D transforms" is still the clearest explanation of perspective, card flips, cubes, boxes and carousels in CSS. Once a cube is built, animating it is ordinary keyframes: rotate the container, and the faces come along.

The keyframe trick for a word cube is the hold. Rotate a quarter turn, hold, rotate again, so each face is readable for a beat. Multiple percentages per pose do it with no JavaScript.

Our Cube Rotate below rolls a four-sided cube forward one face at a time on a 6 s loop. Each face sits at `rotateX(calc(var(--i) * 90deg))` and `translateZ` of half the cube, inside a parent with `perspective`.

Watch out for: 3D rotation of large elements is one of the motion patterns that can trigger vestibular symptoms. Keep cubes small, and stop them under `prefers-reduced-motion`.

10. Bramus: the same keyframes, driven by scroll: Best for reveal-on-scroll without JavaScript

Platform: CSS animation-timeline (Chromium, Safari 26)

Reveal
Live from our directory: Reveal Up On Scroll. Copy the HTML and CSS →

Keyframes no longer have to run on the clock. With `animation-timeline: view()`, an ordinary `@keyframes` rule plays as the element scrolls through the viewport, and `animation-range` sets where it starts and ends. Bramus, a Chrome developer relations engineer, maintains scroll-driven-animations.style with demos such as reading progress indicators, cover flow, stacking cards and image reveals, plus visualisers for the timelines and a DevTools debugger.

The best part: the keyframes are unchanged. A fade-up written for page load works on scroll by swapping the timeline, and Chrome's article notes these animations can run off the main thread.

Our Reveal Up On Scroll below wipes into view from the bottom edge with a shrinking `clip-path` inset as it scrolls in. Browsers without scroll timelines get a one-time animation on load instead.

Watch out for: Scroll-driven progress follows the scroll position, not the clock, so a reduced-motion rule that only shortens `animation-duration` is not a reliable way to stop them. Set `animation: none` for them under `reduce`.

Chrome: scroll-driven animations ↗

11. View Transitions: keyframes on snapshots: Best for page changes and theme switches

Platform: Browser API, styled with @keyframes

Reveal
Live from our directory: Circle Reveal. Copy the HTML and CSS →

View Transitions are keyframe animations too. When a same-document or cross-document view transition runs, the browser snapshots the old and new states into pseudo-elements, and the default crossfade is a pair of CSS animations on them. Replace those animations with your own `@keyframes` and you control how one page or state becomes the next.

A popular custom transition is a circular reveal: the new state grows out of a circle `clip-path` from the point you clicked, often used for dark mode toggles. Same-document transitions are supported in Chrome and Edge 111, Firefox 144 and Safari 18, according to Chrome's docs.

Our Circle Reveal below is the same iris effect on a single element: a `clip-path` circle grows from the centre over 0.9 s until the whole box shows.

Watch out for: Full-screen reveals are large motion. Keep them under half a second in a product, and fall back to a plain crossfade under reduced motion.

12. Our Staggered Grid Pop: one keyframe, many delays: Best for dashboards, galleries and feature grids on first load

Platform: Motions directory, free, pure CSS Ours

Live from our directory: Staggered Grid Animation. Copy the HTML and CSS →

Stagger is the pattern that makes a grid feel choreographed, and it needs only one `@keyframes` rule. Each tile in our Staggered Grid Pop carries a `--i` custom property equal to its row plus its column, and the delay is `calc(var(--i) * 75ms)`. Tiles on the same diagonal land together, so the grid fills like a wave from the top-left corner.

Each tile overshoots to 115 percent, dips to 96 percent and settles, with a separate curve on each leg, and `both` fill mode keeps tiles hidden until their turn.

Like every snippet in our directory, the copy includes a scoped `prefers-reduced-motion` guard that jumps every tile straight to its final state, plus custom properties for colour and size.

Watch out for: Delays add up: on a large grid the last tile can wait over a second. Cap the index, or stagger only what is above the fold.

13. Our Keyframe Animations directory: 90 patterns to start from: Best for copying a working @keyframes rule instead of writing one

Platform: Motions directory, free, pure CSS Ours

Every example on this page comes from one place: our Keyframe Animations directory, 90 copy-paste animations grouped as entrances, exits, attention seekers, loops and scroll-triggered effects. Each is plain HTML and CSS with no JavaScript, and each entry names its curve and timing in its description so you know what you are copying.

Every snippet uses two custom properties, `--kfa-color` and `--kfa-size`, with everything inside sized in `em`, so you can recolour and rescale it in one place. The copy you paste includes a `prefers-reduced-motion` guard scoped to that snippet.

If you need something the directory does not have, the creator writes new keyframes from a description or from your own component.

Watch out for: Directory demos use showcase timings so you can see them. For product UI, shorten most entrances to 200 to 300 ms; our duration guide has the numbers.

14. Our creator: keyframes written to your brief: Best for a custom keyframe animation for your own component

Platform: Motions creator (paid plans; a full run is free to try) Ours

When no pattern fits, describe the animation, or paste your component as HTML or a screenshot, and our creator answers with production-ready CSS keyframes. It asks up to four quick questions while it takes shape: what triggers it, how long, how it should feel, what happens with reduced motion.

Be specific about the pattern from this page you want: "multi-step like a heartbeat", "staggered by index", "steps() typewriter for 24 characters", "exit then remove on animationend". Then refine in chat and export the CSS.

For curves to put in the brief, our easing function examples list the exact cubic-bezier values.

Watch out for: Ask for transform and opacity unless you need something else. Generated animations, like hand-written ones, sometimes reach for width, top or box-shadow when a cheaper property would do.

How to choose the right keyframe pattern

Most keyframe animations fall into one of five patterns. Pick by what the animation has to do.

Match it to the job

Arriving: a one-shot entrance with fill mode both (Back In Up, Puff In). Leaving: an exit that keeps its last frame and fires animationend (Hinge, Fade Out). Asking for attention: a short multi-step loop with rests (Heartbeat, Ping). Showing work: a linear or stepped loop. Responding to scroll: the same keyframes on animation-timeline: view().

Match it to how many elements

One element: write the keyframes directly. Many similar elements: one keyframe rule plus a --i custom property for the delay (Staggered Grid Pop). A whole view or page change: View Transitions, styled with your own keyframes. If an animation needs to reverse when interrupted, such as hover or open and close, use a transition instead of keyframes.

Match it to your stack

Plain CSS: copy from our directory or Animista and keep only what you use. Tailwind: built-in animate-spin, ping, pulse and bounce, or your own via @theme. A site that already loads Animate.css: its classes and --animate-duration. JavaScript needed for sequencing or physics: keep the keyframes for simple parts and hand the rest to the Web Animations API or a library.

Copy one pattern and make it yours

Open the pattern closest to what you need in the Keyframe Animations directory, copy the CSS, then change three things: the duration, the curve and the distance. Those three numbers turn a stock animation into one that fits your product.

If you would rather start from a description, our creator writes the keyframes for you and keeps the reduced-motion guard in.

A prompt to start from
Make a staggered entrance for a 3 by 4 grid of feature cards in pure CSS @keyframes.
Each card fades in and rises 16px over 320 ms on cubic-bezier(0.22, 1, 0.36, 1), with a tiny overshoot.
Stagger by a --i custom property at 60 ms per step along the diagonal, capped at 8 steps.
Use fill mode both. Under prefers-reduced-motion, show every card immediately with no movement.

Make your own with AI →

Common questions

What is @keyframes in CSS?

@keyframes is the CSS at-rule that defines the states of an animation, using from and to or percentages from 0% to 100%. You then apply it to an element with the animation property, giving it a duration, timing function, iteration count, direction and fill mode.

What is the difference between CSS keyframes and transitions?

A transition animates between two states when a property changes, such as on hover, and reverses smoothly if interrupted. Keyframe animations can have any number of steps, can loop, and start as soon as they are applied, which makes them right for entrances, loops and choreography.

How do I keep the final state after a CSS animation ends?

Use animation-fill-mode: forwards to keep the last keyframe, or both to also apply the first keyframe during any delay. Without a fill mode, the element snaps back to its normal styles when the animation ends.

Can I use multiple @keyframes animations on one element?

Yes. List them comma-separated in the animation property, for example a typing animation and a caret blink, and every animation longhand accepts a matching comma-separated list of values.

How do I make CSS keyframes respect reduced motion?

Wrap the animation in @media (prefers-reduced-motion: no-preference), or override it inside @media (prefers-reduced-motion: reduce) with a near-zero duration and an iteration count of 1. For scroll-driven animations, set animation: none instead, since their progress follows scroll rather than time.

Sources