Free · Fast · Privacy-first

CSS Animated Background Generator

Animating a CSS background does not require JavaScript, a canvas, or a third-party library, and most of the moving gradients you see on modern landing pages come down to a few lines of @keyframes targeting background-position.

Generates @keyframes CSS for animated background-position effects

🔒

Configurable animation-duration and animation-timing-function

Moving gradient, scrolling stripe, and colour shift presets

Performance notes included for each animation type

Cost
Free forever
Sign-up
Not required
Processing
In your browser
Privacy
Files stay local
FreeNo signupWhite-label

Add this Background Gen to your website

Drop the Background Gen into any page — blog post, product docs, intranet, school portal — with a single line of HTML. Your visitors get the full tool, processed entirely in their browser. No backend, no uploads, no signup.

  • Files stay 100% in the visitor's browser
  • Responsive — adapts to any container width
  • Free forever, no API key needed

Embed code

<iframe
  src="https://www.fixtools.io/css-tool/background-gen?embed=1"
  width="100%"
  height="780"
  frameborder="0"
  style="border:0;border-radius:16px;max-width:900px;"
  title="Background Gen by FixTools"
  loading="lazy"
  allow="clipboard-write"
></iframe>

Attribution-friendly: a small "Powered by FixTools" link appears in the embed footer.

Animating CSS Backgrounds with @keyframes: Techniques and Performance

CSS gradient values cannot be directly animated because gradients are computed image types rather than scalar values, and browsers cannot interpolate between two gradient definitions inside a keyframe rule. The standard workaround is to animate background-position on a gradient sized larger than the element. Set background-size: 200% 200% on a diagonal gradient, then animate background-position from 0% 0% to 100% 100%. As the position shifts, different parts of the oversized gradient become visible inside the element, creating an apparent colour shift animation that looks indistinguishable from interpolating between gradients. The animation loops seamlessly because the gradient is symmetric: the 0% 0% and 100% 100% positions land on the same visual due to how the oversized gradient tiles inside the element.

Scrolling stripe patterns use repeating-linear-gradient combined with background-position animation. Set repeating-linear-gradient(45deg, transparent 0px, transparent 20px, rgba(255,255,255,0.1) 20px, rgba(255,255,255,0.1) 40px) as the background, then animate background-position-x from 0px to 40px so the keyframe end matches the stripe pitch exactly. The animation loops seamlessly at the tile boundary, creating continuously moving diagonal stripes. This technique powers most loading bars, progress indicators, and active-state visualisations you see in modern UI kits. Keep the stripe animation to looping translation rather than animating the colours inside the stripes, since translation composites cheaply on the GPU while colour interpolation forces repaints.

Performance is the primary concern for animated backgrounds, especially on full-viewport sections. background-position animation can cause main-thread repaints on browsers that do not composite the background independently of the element content. Test using the Chrome DevTools Rendering panel with Paint Flashing enabled and watch what happens during an animation cycle. If the element flashes green on every animation frame, the animation is triggering main-thread repaints and will cost frame budget on lower-end devices. Adding will-change: background-position hints the browser to promote the element to its own compositing layer in Chrome and Firefox, moving the animation off the main thread. Keep background-size as small as the effect allows.

Accessibility deserves the same attention as performance. Continuous background animations can trigger motion sickness or vestibular discomfort for some users, and the WCAG 2.1 success criterion on motion from animation recommends offering a way to pause or disable animations. Wrap your animation declaration in @media (prefers-reduced-motion: no-preference) so the animation only activates for users who have not asked for reduced motion. Pair this with the underlying static background defined outside the media query, so users on reduced-motion settings see the same gradient or pattern without the movement. This pattern delivers visual polish to most users while quietly disappearing for the audience that needs the accommodation.

How to use this tool

💡

Select an animation preset (moving gradient, scrolling stripes, or animated colour shift), set animation duration in seconds, and choose an easing function. The tool generates the background CSS and the @keyframes block. Copy both sections and paste them into your stylesheet.

How It Works

Step-by-step guide to css animated background generator:

  1. 1

    Select an animation preset

    Choose a moving gradient, scrolling stripe, shimmer skeleton, or animated colour shift preset from the picker. The preview starts the animation immediately in the tool so you can judge the visual character at the actual speed before changing any settings, which avoids the slow loop of edit, save, refresh that wastes time on keyframe work.

  2. 2

    Set animation duration

    Enter the duration in seconds based on the role of the animation. Use 0.5 to 2 seconds for loading indicators and skeleton shimmer, 3 to 8 seconds for noticeable active backgrounds, and 15 to 30 seconds for subtle ambient movement that lives in the periphery without drawing the eye away from the primary content.

  3. 3

    Choose an easing function

    Select linear for continuous looping motion such as scrolling stripes and shifting gradients, or ease-in-out for gentle pulsing effects where the animation has a clear start and end inside each cycle. Linear is the right choice for the vast majority of looping animations because any easing creates a perceptible stutter at the loop point.

  4. 4

    Copy the CSS and keyframes

    Copy both the background declaration block and the @keyframes block in one paste. The tool wraps the animation in a prefers-reduced-motion media query by default so the static background is the baseline and the animation is opt-in for users who have not requested reduced motion. Paste directly into your stylesheet without further edits.

Real-world examples

Common situations where this approach makes a real difference:

Developer animating a loading skeleton gradient

A developer creates a loading skeleton screen where placeholder cards display an animated shimmer effect while data fetches in the background. They use a linear gradient from #e2e8f0 to #f8fafc to #e2e8f0 with background-size: 200% 100% and animate background-position from 100% 0 to -100% 0 over 1.5 seconds with linear timing and infinite iteration. The shimmer moves left to right across each skeleton card, signalling loading state in the same visual language users recognise from Facebook, LinkedIn, and most modern web apps, all without a single line of JavaScript or a third-party skeleton library.

Designer adding an animated gradient to a pricing hero

A designer wants a slowly shifting gradient background on the pricing page hero to add visual interest without distracting from the pricing tiles. They use a diagonal gradient with background-size: 300% 300% across four brand colours and animate background-position from 0% 50% to 100% 50% and back in a 12-second linear loop. The animation is wrapped in @media (prefers-reduced-motion: no-preference) so users with motion sensitivity see the static gradient as the fallback, and the colours of the static gradient are tuned so the page looks intentional in both the animated and static states.

Engineer building an animated progress bar

An engineer implements a striped progress bar for a file upload indicator with a custom brand colour rather than the default browser progress styling. They use repeating-linear-gradient(45deg, rgba(255,255,255,0.15) 0px, rgba(255,255,255,0.15) 10px, transparent 10px, transparent 20px) layered over a solid green background, then animate background-position-x from 0 to 20px in a 0.5s linear infinite loop so the stripes flow continuously toward the right. The result matches the visual language of native striped progress bars while remaining fully styleable, themeable, and accessible to the design system tokens.

Student exploring CSS animation performance

A student tests animated background-position on a full-page section and notices visible scroll jank that did not appear with a static background. They enable Paint Flashing in Chrome DevTools and see the entire element repainting on every animation frame, which explains the dropped frames. Adding will-change: background-position to the element stops the flashing, confirming the animation has moved to GPU compositing on a dedicated layer. The exercise teaches them the practical difference between composited and non-composited CSS properties and demystifies why the same animation behaves differently across browsers and devices.

Pro tips

Get better results with these expert suggestions:

1

Use @property to animate gradient colour stops in Chrome and Firefox

@property allows declaring a custom property with a specific type. Declaring @property --gradient-hue { syntax: "<angle>"; inherits: false; initial-value: 0deg; } and animating --gradient-hue in a keyframe creates a colour-shifting gradient. Chrome and Firefox support this; Safari requires a fallback. Declare the animation with the @supports rule to apply it only where supported.

2

Keep animated background-size small to reduce GPU memory

A 200% 200% background-size on a full-viewport element allocates a compositing surface four times the viewport area. On a 1920x1080 display this is a 3840x2160 GPU texture. Use the smallest background-size that achieves the visual effect. For scrolling stripes, the background can be the element size with a small tile rather than an oversized gradient.

3

Use animation-play-state: paused to freeze on hover

Set animation-play-state: running by default and animation-play-state: paused on :hover. This pauses the background animation when the user hovers the element, which can be useful for interactive cards or buttons where the animation draws attention until the user interacts.

4

Test animation at animation-duration: 20s for subtle background shifts

Very slow background colour animations (20-30 seconds per cycle) are barely perceptible consciously but create a sense of life in a static page. This duration avoids the motion sickness risk of fast animations and is subtle enough to remain appropriate for most contexts.

5

Match keyframe end to tile boundary for seamless loops

For tiling pattern animations, set the final keyframe background-position to exactly the background-size value. A 40px stripe tile animated from 0px to 40px completes one full tile cycle and loops without a visible jump.

6

Use animation-timing-function: linear for smooth movement

Easing functions like ease-in-out produce a speed change at the start and end of each animation cycle. For continuously moving backgrounds, animation-timing-function: linear keeps movement at constant speed and avoids a perceptible stutter at the loop point.

7

Respect prefers-reduced-motion for animated backgrounds

Wrap the animation declaration in @media (prefers-reduced-motion: no-preference). Users with motion sensitivity or vestibular disorders should see a static background. Animated backgrounds that cover large screen areas are especially likely to cause discomfort.

FAQ

Frequently asked questions

Not directly. Gradient values are computed images, and CSS cannot interpolate between two gradient definitions in a keyframe. The standard workaround is to animate background-position on a gradient sized larger than the element using background-size: 200% 200% or more. As background-position shifts, different parts of the oversized gradient become visible, creating an apparent colour change. The @property approach can animate individual colour stop values in Chrome and Firefox with a typed custom property declaration.
Set the pattern as a repeating background using a tiling gradient, then animate background-position or background-position-x using @keyframes. Set the end keyframe position to the exact background-size tile value for a seamless loop: if background-size is 40px 40px, animate from 0px 0px to 40px 40px. Use animation-timing-function: linear and animation-iteration-count: infinite. This creates a continuously moving tiled pattern.
Jank in animated backgrounds usually means the animation is triggering main-thread repaints instead of being composited on the GPU. Check with Chrome DevTools Paint Flashing. Adding will-change: background-position hints to the browser to promote the element to its own compositing layer. Also ensure the animation frame rate is not reduced by heavy JavaScript running on the same frame. Keeping background-size small reduces GPU texture memory consumption.
Create a multi-stop gradient larger than the element: background: linear-gradient(135deg, #3b82f6, #8b5cf6, #ec4899, #3b82f6) with background-size: 300% 300%. Animate background-position from 0% 0% to 100% 100% in a looping keyframe. The gradient shifts as different sections become visible. Using the same colour at the start and end of the gradient stops ensures the loop is seamless.
For loading shimmer effects, 1-2 seconds is typical. For active UI state indicators (progress bars, active tabs), 0.5-1 second works. For ambient background colour shifts intended as a subtle visual effect, 15-30 seconds keeps movement imperceptible at a glance while still creating a sense of motion. Avoid animation durations under 0.5 seconds on backgrounds covering large areas as rapid movement increases motion sickness risk.
Wrap the animation declaration in @media (prefers-reduced-motion: no-preference) { .element { animation: ... } }. This applies the animation only when the user has not set a preference for reduced motion. Users who have set reduce motion in their OS accessibility settings will see the static background version. As a fallback, define the static background properties outside the media query so the element still displays correctly without animation.
Yes, with care. Limit animated backgrounds to small elements rather than full-page sections on mobile. Use will-change: background-position to promote the element to a GPU layer. Avoid background-size larger than 200% as it allocates a large GPU texture. Test on a physical mid-range Android device: mobile GPU performance varies far more than desktop, and an animation that runs smoothly in browser devtools emulation may drop frames on a budget phone.
background-color is a scalar colour value and can be directly transitioned or animated between two colour values. The browser interpolates smoothly between them. background-position is a pair of length or percentage values that move the background image origin. Animating background-position shifts the image rather than changing a colour. For a colour shift effect on a gradient, animating background-position on an oversized gradient is the standard approach since gradients themselves are images rather than colours and cannot be interpolated directly. The performance characteristics also differ: background-color animations tend to repaint while background-position animations can often be promoted to a GPU compositing layer with will-change, which is why background-position is preferred for any large animated surface.
Yes, by combining the Page Visibility API with a class toggle that swaps animation-play-state. Add a small script that listens for the visibilitychange event and toggles a .paused class on the body when document.hidden becomes true. In the CSS, write body.paused .animated-bg { animation-play-state: paused; }. This stops the animation when the tab is in the background, which reduces battery drain on laptops and phones and frees the GPU for other work. When the user returns to the tab the class is removed and the animation resumes from where it left off without restarting from the first keyframe.

Ready to get started?

Open the full Background Gen — free, no account needed, works on any device.

Open Background Gen →

Free · No account needed · Works on any device