Search code examples
svgsvg-animate

How can I animate the gradient of this SVG to cycle from red to blue, top to bottom repeatedly?


How can I change this SVG so that the gradient cycles from top to bottom continuously such that when the red is dropping off the bottom, it is appearing from the top and when the blue is dropping off the bottom, it is appearing from the top.

This is what I have so far:

<svg width="300px" height="500px" viewBox="0 0 180 336">
  <rect x="80" y="50" width="20" height="100" fill="none" stroke="url(#grad)" stroke-linecap="round" stroke-linejoin="round" stroke-width="20"/>
   <defs>
      <linearGradient id="grad" x1="0%" y1="0%" x2="0%" y2="100%">
         <stop offset="0%" stop-color="red">
            <animate attributeName="stop-color" dur="3s" repeatCount="indefinite" values="red;blue;red;"></animate>
         </stop>
         <stop offset="100%" stop-color="blue">
            <animate attributeName="stop-color" dur="3s" repeatCount="indefinite" values="blue;red;blue"></animate>
         </stop>
       </linearGradient>
   </defs>
</svg>

https://jsfiddle.net/hq7vfL98/

This has the appearance of bouncing from top to bottom rather than cycling as described.


Solution

  • Don't animate the color, animate the y1 y2 attributes. You can take advantage of the spreadMethod attribute to cycle forth and back from one color to the other.

    <svg width="300px" height="500px" viewBox="0 0 180 336">
      <rect x="80" y="50" width="20" height="100" fill="none" stroke="url(#grad)" stroke-linecap="round" stroke-linejoin="round" stroke-width="20"/>
       <defs>
          <linearGradient id="grad" x1="0%" y1="0%" x2="0%" y2="100%" spreadMethod="reflect">
              <animate attributeName="y1" dur="3s" repeatCount="indefinite" from="0%" to="200%" />
              <animate attributeName="y2" dur="3s" repeatCount="indefinite" from="100%" to="300%" />
             <stop offset="0%" stop-color="red" />
             <stop offset="100%" stop-color="blue" />
           </linearGradient>
       </defs>
    </svg>