Search code examples
animationsvgalpha-transparency

How can I loop colors and maintain edge transparency with an SVG radial animation?


I have a disc-shaped SVG to which I would like to apply a set of colors that radiate from the center outwards in a loop while also maintaining edge (i.e. stop-opacity) transparency, similar to what is present if the object does not have an applied animation.

Here are the to main hurdles on the animated version:

  1. The edge transparency is not retained. In some cases, I might tackle this by overlaying a similar shape to accommodate the edge transparency with a color complimentary to the the target object's background color -- but in this case the object is sitting atop gradient.

  2. The loop resets at the configured value values="1%; ...", rather than smoothly looping/cycling the colors. Not sure how to get around this, or if it's even possible with a radial animation.

Thanks in advance for any thoughts/recommendations!

<div style="background: linear-gradient(#231f20 0%, #231f20 21%, rgba(31, 28, 29, 0.89) 49%, rgba(20, 18, 18, 0.57) 74%, rgba(1, 1, 1, 0.02) 99%, rgba(0, 0, 0, 0) 100%);">
  <svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"
       xmlns:xlink="http://www.w3.org/1999/xlink" width="300" style="display:inline-block;">
    <defs>
      <radialGradient id="gradient"> 
      <stop offset="0%" stop-color="#d6d2c4"/>
      <stop offset="24%" stop-color="#ffd600"/>
      <stop offset="42%" stop-color="#a6cd57"/>
      <stop offset="61%" stop-color="#f8971f"/>
      <stop offset="100%" stop-color="#f8971f" stop-opacity="0"/>
    </radialGradient>
    </defs>

    <!-- radial gradient animation -->
    <circle cx="5" cy="5" r="4" fill="url('#gradient')" />
  </svg>
  <svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"
       xmlns:xlink="http://www.w3.org/1999/xlink" width="300" style="display:inline-block;">
    <defs>
      <radialGradient id="gradientAnimate"> 
  <stop offset="0%" stop-color="#d6d2c4"/>
  <stop offset="10%" stop-color="#ffd600"/>
  <stop offset="20%" stop-color="#a6cd57"/>
  <stop offset="30%" stop-color="#f8971f"/>
  <stop offset="40%" stop-color="#f8971f"/>
  <stop offset="50%" stop-color="#d6d2c4"/>
  <stop offset="70%" stop-color="#ffd600"/>
  <stop offset="80%" stop-color="#a6cd57"/>
  <stop offset="90%" stop-color="#f8971f"/>
  <stop offset="100%" stop-color="#f8971f" stop-opacity="0"/>
		<animate attributeName="r" dur="5s" repeatCount="indefinite"
           values="50%; 100%; 300%" />
</radialGradient>
    </defs>

    <!-- radial gradient animation -->
    <circle cx="5" cy="5" r="4" fill="url('#gradientAnimate')" />
  </svg>
</div>


Solution

  • A solution to your problem would be applying a mask: a circle with a radial gradient from white to black:

    <div style="background: linear-gradient(#231f20 0%, #231f20 21%, rgba(31, 28, 29, 0.89) 49%, rgba(20, 18, 18, 0.57) 74%, rgba(1, 1, 1, 0.02) 99%, rgba(0, 0, 0, 0) 100%);">
      <svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"
           xmlns:xlink="http://www.w3.org/1999/xlink" width="300" style="display:inline-block;">
        <defs>
          <radialGradient id="gradient"> 
          <stop offset="0%" stop-color="#d6d2c4"/>
          <stop offset="24%" stop-color="#ffd600"/>
          <stop offset="42%" stop-color="#a6cd57"/>
          <stop offset="61%" stop-color="#f8971f"/>
          <stop offset="100%" stop-color="#f8971f" stop-opacity="0"/>
        </radialGradient>
        </defs>
    
        <!-- radial gradient animation -->
        <circle cx="5" cy="5" r="4" fill="url('#gradient')" />
      </svg>
      <svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg"
           xmlns:xlink="http://www.w3.org/1999/xlink" width="300" style="display:inline-block;">
        <defs>
      <radialGradient id="rg">
       <stop offset="50%" stop-color="#fff"></stop>
       <stop offset="100%" stop-color="#000"></stop>
      </radialGradient>
      <mask id="maskCirc">
       <circle cx="5" cy="5" r="4" fill="url(#rg)"></circle>
      </mask>
          
          <radialGradient id="gradientAnimate"> 
      <stop offset="0%" stop-color="#d6d2c4"/>
      <stop offset="10%" stop-color="#ffd600"/>
      <stop offset="20%" stop-color="#a6cd57"/>
      <stop offset="30%" stop-color="#f8971f"/>
      <stop offset="40%" stop-color="#f8971f"/>
      <stop offset="50%" stop-color="#d6d2c4"/>
      <stop offset="70%" stop-color="#ffd600"/>
      <stop offset="80%" stop-color="#a6cd57"/>
      <stop offset="90%" stop-color="#f8971f"/>
      <stop offset="100%" stop-color="#f8971f" stop-opacity="0"/>
    		<animate attributeName="r" dur="5s" repeatCount="indefinite"
               values="50%; 100%; 300%" />
    </radialGradient>
        </defs>
    
        <!-- radial gradient animation -->
        <circle cx="5" cy="5" r="4" fill="url('#gradientAnimate')" style="mask: url(#maskCirc);"/>
      </svg>
    </div>