Guides/Animated CSS Gradients

How to Create Animated CSS Gradients

Animating CSS gradients is more nuanced than it looks — transitiondoesn't work on gradient values because browsers don't treat them as animatable. But there are several well-supported techniques to achieve smooth gradient animation using only CSS. This guide covers four approaches, when to use each, and working code examples.

For a no-code approach, use the Animated Gradient Generator to create and export animated gradient CSS instantly.

Why you can't animate gradients directly

The CSS transition and animation properties only interpolate between values that the browser knows how to interpolate. Gradient functions like linear-gradient(#3b82f6, #8b5cf6)are treated as opaque image values — browsers won't interpolate between two different gradient declarations.

The workaround is to animate a property that affects the gradient appearance rather than the gradient itself — background-position, filter, opacity, or a CSS custom property used inside the gradient.

Technique 1 — Background-position shift

Create an oversized gradient (200–400% wide) and animate background-position to scroll through it. This creates the classic moving gradient effect seen on many landing pages.

.animated-gradient {
  background: linear-gradient(
    270deg,
    #3b82f6,
    #8b5cf6,
    #ec4899,
    #3b82f6  /* repeat start color for seamless loop */
  );
  background-size: 300% 300%;
  animation: gradient-shift 6s ease infinite;
}

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

The gradient must repeat the starting color at the end for a seamless loop. background-size must be larger than 100% to give the animation room to move.

Technique 2 — Hue-rotate filter

Animating filter: hue-rotate()rotates all colors through the hue wheel. The simplest technique — one CSS rule — but you can't control which colors appear; it cycles through the full spectrum.

.hue-animated {
  background: linear-gradient(135deg, #3b82f6, #8b5cf6);
  animation: hue-cycle 4s linear infinite;
}

@keyframes hue-cycle {
  from { filter: hue-rotate(0deg); }
  to   { filter: hue-rotate(360deg); }
}

Best for rainbow or spectrum effects. Not suitable when you need specific brand colors to stay stable.

Technique 3 — CSS @property

Using @property to register a typed CSS custom property allows the browser to interpolate it like a number or color — enabling true gradient animation via CSS variables.

@property --gradient-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

.rotating-gradient {
  background: linear-gradient(
    var(--gradient-angle),
    #3b82f6,
    #8b5cf6
  );
  animation: rotate-gradient 4s linear infinite;
}

@keyframes rotate-gradient {
  from { --gradient-angle: 0deg; }
  to   { --gradient-angle: 360deg; }
}

Browser support: Chrome 85+, Edge 85+, Safari 16.4+. Firefox does not yet support @property. Include a background-position fallback for Firefox users.

Technique 4 — Opacity crossfade

Stack two gradient elements and animate their opacity. Smooth, fully compatible, and allows transitioning between completely different gradient compositions.

.gradient-a {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, #3b82f6, #8b5cf6);
  animation: fade-ab 4s ease infinite alternate;
}

.gradient-b {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, #ec4899, #f59e0b);
  animation: fade-ab 4s ease infinite alternate-reverse;
}

@keyframes fade-ab {
  from { opacity: 1; }
  to   { opacity: 0; }
}

Performance notes

Tailwind CSS animated gradient

Tailwind doesn't include built-in gradient animation utilities, but you can add custom keyframes in tailwind.config.js:

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      animation: {
        'gradient-shift': 'gradient-shift 6s ease infinite',
      },
      keyframes: {
        'gradient-shift': {
          '0%, 100%': { backgroundPosition: '0% 50%' },
          '50%': { backgroundPosition: '100% 50%' },
        },
      },
    },
  },
}

// JSX usage
<div className="bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500 bg-[length:300%_300%] animate-gradient-shift" />