Dec 5, 2023

Animating Gradients in CSS

Have you ever tried to animate a background in CSS with a linear-gradient? If so, then you most likely stumbled upon the same issue as I did.

The following code show’s the most simple approach I would start with, when it comes to animate the background.

css
body {
    margin: 0;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    animation: animate-bg 2s infinite;
}

@keyframes animate-bg {
  from {
      background: linear-gradient(yellow, dodgerblue);
  }
  to {
      background: linear-gradient(dodgerblue, yellow);
  }
}

We define an animation on the body element which changes the gradient background from black-white to white-black.

However, we can see that it doesn’t work as expected. The color changes immediately, without any animation or smooth transition.

Figure 1: What we see on the screen with the styles from above

How to solve it

Some solutions to this are animating the background-position which generates the same effect. We can see it in the following code:

css
body {
    background: linear-gradient(-45deg, #EA225E, #C22286, #612E8D);
    background-size: 200% 200%;
    animation: GradientBackground 10s ease infinite;
}

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

However, it somehow feels hacky to me, as we need to define an extra large background of which we then animate a changing position. Why can’t we just flip the colors of the gradient?

A better approach — using modern CSS @property

With the release of the CSS Properties and Values API, we actually can do this! This API exposes low-level functionality of the CSS rendering engine, enabling developers with more powerful styling.

In our case, we define a new CSS Custom Property. However, we use the @property syntax to declare it.

By setting the syntax property, we can specify the exact type of property, such as color, number, length, and many more.

css
@property --gradPoint {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}

Instead of changing the background property in our animation, we change the value of the colors of it. To make it work, we define two color variables using the @property syntax.

Then, we define an animation which changes their color from black to white and vice versa.

Finally, we apply this animation to our body element.

css
body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  animation: animate-color 3s ease-in-out infinite alternate;
  background: linear-gradient(var(--color), var(--color-second));
}

@keyframes animate-color {
  to {
      --color-1: yellow;
      --color-2: dodgerblue;
  }
}

@property --color {
  syntax: '<color>';
  inherits: false;
  initial-value: red;
}

@property --color-second {
  syntax: '<color>';
  inherits: false;
  initial-value: blue;
}

And this is what we get

Figure 2: A smooth transition between the colors of the gradient

A smooth transition between the color changes 🎉


Newsletter

Subscribe to get notified about new articles and updates.

Thanks for subscribing! You will receive an email shortly.