Home / Snippets / Color & Theming /

Animated background

A slowly shifting gradient background using @keyframes, background-size: 200% 200%, and background-position animation.

Gradient in motion
Widely Supported
coloranimationno-js

Quick implementation

.animated-bg {
  background: linear-gradient(
    135deg,
    oklch(0.30 0.18 280),
    oklch(0.42 0.20 240),
    oklch(0.35 0.16 200),
    oklch(0.28 0.14 260)
  );
  background-size: 200% 200%;
  animation: bg-shift 8s ease infinite;
}

@keyframes bg-shift {
  0%   { background-position: 0%   50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0%   50%; }
}

@media (prefers-reduced-motion: reduce) {
  .animated-bg {
    animation: none;
    background-position: 0% 50%;
  }
}

Prompt this to your LLM

Includes role, constraints, two framework variants, and edge cases to handle.

You are a senior frontend engineer building a CSS animation library.

Goal: A smoothly animating gradient background using @keyframes and background-position — no JavaScript.

Technical constraints:
- Use a linear-gradient with at least four oklch() color stops at 135deg.
- Set background-size: 200% 200% to create a larger canvas than the element.
- Animate background-position from 0% 50% to 100% 50% and back using @keyframes.
- Use an infinite loop with ease timing and a duration between 6s and 12s for a slow, ambient feel.
- Use oklch() for all colors — no hex or rgba().
- Include @media (prefers-reduced-motion: reduce) to freeze the animation at a static position.

Framework variant (pick one):
A) Vanilla CSS utility class that can wrap any element.
B) React component — accept colors array, duration, and angle as optional props.

Edge cases to handle:
- Ensure the gradient direction and color stops are tuned so no abrupt color jump occurs at the loop boundary.
- The static fallback (reduced-motion) should still look intentional, not broken.
- Works on both block-level containers and inline elements with display: inline-block.

Return CSS.

Why this matters in 2026

Animated gradient backgrounds are one of the most requested UI effects for hero sections, loading states, and ambient UI. The background-position trick achieves smooth color shifting without animating gradient stops directly — which would force full repaints. This approach keeps the animation cheap and is supported in every modern browser without JavaScript or a canvas element.

The logic

The gradient is painted on a canvas twice the element's width and height (background-size: 200% 200%). The @keyframes rule shifts the viewport over this larger canvas by animating background-position — moving from the left edge to the right edge and back. Because the gradient has multiple overlapping color stops, panning across it produces a smooth color transition rather than a sharp jump. Crucially, background-position is a composited property in most browsers, so the animation runs without triggering layout or paint recalculation.

Accessibility & performance

Always include @media (prefers-reduced-motion: reduce) to stop the animation for users with vestibular sensitivities — a looping background shift is exactly the kind of movement this preference is designed to address. From a performance perspective, animating background-position is far cheaper than animating background-image or swapping gradient definitions. Keep the duration above 6 seconds; fast-cycling gradients are distracting and create unnecessary GPU work.