Keyframe
Keyframe · The log

Animated Gradient Background in CSS: Smooth, Cheap, and Not Nauseating

July 24, 2026 · Uncategorized

An animated gradient is one of those effects that looks expensive and costs almost nothing. Colors drifting slowly behind a hero section, a login card, a loading screen. Done gently it feels premium. Done badly it strobes like a screensaver from 1998 and gives people a headache. The line between the two is mostly speed.

The oversized-background trick

You cannot animate the colors inside a gradient directly. What you can do is make the gradient much larger than its box and slide it around, which the eye takes as the colors shifting. Set background-size to something like 300 percent, then animate background-position.

.aurora {
  background: linear-gradient(120deg, #ff3d7f, #7b2ff7, #14e0c3, #ff3d7f);
  background-size: 300% 300%;
  animation: drift 12s ease infinite;
}

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

The duration does the work here. Twelve seconds per cycle is slow enough that the movement sits below conscious notice, which is exactly where you want an ambient background. People should feel it more than see it. Anything under about six seconds starts pulling the eye away from the actual content, and that is the opposite of what a background is for.

Repeating the first color at the end of the gradient stops a hard jump when the loop restarts. Since the keyframes return to 0% 50%, the seam lands on a matching color and the loop becomes invisible.

A spinning conic gradient

For something with more energy, a conic gradient rotated around its center gives that slow color-wheel sweep. It needs a modern browser and a small assist, because you cannot animate conic-gradient angles the old way. The clean route is rotating the whole layer.

.wheel {
  position: relative;
  overflow: hidden;
}

.wheel::before {
  content: "";
  position: absolute;
  inset: -50%;
  background: conic-gradient(from 0deg, #ff3d7f, #7b2ff7, #14e0c3, #ff3d7f);
  animation: turn 18s linear infinite;
}

@keyframes turn {
  to { transform: rotate(360deg); }
}

The pseudo-element is set to inset: -50% so its corners stay covered as it rotates, and the parent clips the overflow. Rotating a transform is compositor-friendly, so even this heavier look stays smooth.

Watch the battery

One downside nobody mentions. A full-screen gradient animating forever keeps the GPU awake, and on a laptop that shows up as a warm fan and a shorter afternoon. It is fine for a hero the visitor scrolls past in seconds. It is rude on a page someone leaves open all day.

Two mercies. Pause the animation when the section scrolls out of view if you want to be thorough, and always cut it for reduced-motion users, who often set that preference precisely because endless movement bothers them.

@media (prefers-reduced-motion: reduce) {
  .aurora,
  .wheel::before {
    animation: none;
  }
}

A drifting gradient is a mood, not a feature, so treat it lightly. The performance thinking behind keeping it on the GPU is in CSS animation performance, and the reduced-motion pattern comes from accessible animation. The pillar on CSS animation collects the rest.

← Back to the log