SVG gradient offset animation

80 Views Asked by At

I'm working on an SVG animation. But I've encountered a problem... I want to animate a changing gradient offset in my SVG. I use this SVG for this. I have already animated changing colors animation but I can't change the offset of the gradient.

<svg className="SvgContain" width="923" height="382" viewBox="0 0 923 382" fill="none" xmlns="http://www.w3.org/2000/svg">
   <defs>
  <linearGradient id="gradient1">
     <stop className="stop1" offset="0%" stop-color="red">
     </stop>
     <stop className="stop2" offset="100%" stop-color="blue">
     </stop>
  </linearGradient>
   </defs>
   <path className="SvgPath" id="PolygonePath" d="M0.5 381.5L382 0H923V381.5H0.5Z" fill="url(#gradient1)">
</svg>

I tried to use the <animate></animate> tag for creating the effect want to do but it doesn't work. I used this code for this. I asked ChatGPT if the animate tag can handle the animation of the offset. It says yes, I followed the instructions but the animation didn't work.

<svg className="SvgContain" width="923" height="382" viewBox="0 0 923 382" fill="none" xmlns="http://www.w3.org/2000/svg">
   <defs>
  <linearGradient id="gradient1">
     <stop className="stop1" offset="0%" stop-color="red">
        <animate
          attributeName="offset"
          values="0%; 100%"
          dur="5s"
          repeatCount="indefinite">
        </animate>
     </stop>
     <stop className="stop2" offset="100%" stop-color="blue">
        <animate
          attributeName="offset"
          values="100%; 0%"
          dur="5s"
          repeatCount="indefinite">
        </animate>
     </stop>
  </linearGradient>
   </defs>
   <path className="SvgPath" id="PolygonePath" d="M0.5 381.5L382 0H923V381.5H0.5Z" fill="url(#gradient1)">
</svg>

1

There are 1 best solutions below

0
Łukasz D. Mastalerz On

I'm not sure if this is the animation you meant... Take a look at these two methods. I assume using JS is not the problem. In my opinion, this is a better solution because you can control the animation more. Below is a variant with JS and CSS. The CSS is a bit wild but it's a matter of adjusting the frames.

JS option:

const stop1 = document.getElementById('stop1');
let offset = 0;
let speed = 0.2;
let direction = 1;

const animateGradient = () => {
  offset += speed * direction;
  
  if (offset >= 100 || offset <= 0) {
    direction *= -1; 
  }
  stop1.setAttribute('offset', `${offset}%`);
 requestAnimationFrame(animateGradient);
}
animateGradient();
.SvgContain {
      width: 923px;
      height: 382px;
    }
<svg class="SvgContain" viewBox="0 0 923 382" fill="none" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="gradient1" x1="-50%" y1="0%" x2="150%" y2="0%">
      <stop id="stop1" offset="0%" stop-color="red"></stop>
      <stop offset="100%" stop-color="blue"></stop>
    </linearGradient>
  </defs>
  <path class="SvgPath" id="PolygonePath" d="M0.5 381.5L382 0H923V381.5H0.5Z" fill="url(#gradient1)"></path>
</svg>

As you can see, there is a line at the junction of the colors, it doesn't look good, you can manipulate the number of stops to spread the color spectrum.

CSS option

@keyframes moveGradient1 {
  0%, 100% {
    stop-color: red;
    offset: 0%;
  }
  50% {
    stop-color: blue;
    offset: 100%;
  }
}
@keyframes moveGradient2 {
  0%, 100% {
    stop-color: blue;
    offset: 100%;
  }
  50% {
    stop-color: red;
    offset: 0%;
  }
}
.stop1 {
  animation: moveGradient1 4s linear infinite;
}
.stop2 {
  animation: moveGradient2 4s linear infinite;
}
<svg class="SvgContain" width="923" height="382" viewBox="0 0 923 382" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="gradient1">
      <stop class="stop1" offset="0%" stop-color="red"/>
      <stop class="stop2" offset="100%" stop-color="blue"/>
    </linearGradient>
  </defs>
  <path class="SvgPath" id="PolygonePath" d="M0.5 381.5L382 0H923V381.5H0.5Z" fill="url(#gradient1)"></path>
</svg>