Chrome 不适用于线性渐变的属性偏移动画

Chrome doesn’t work on the animation of the attribute offset for a linear gradient

下面是在 Firefox 中运行良好的代码,但在 Chrome 中对线性渐变的偏移属性设置动画的任何尝试都以失败告终。

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
      width="50%" height="50%" viewBox="0 0 900 900" >  

 <defs>
<linearGradient id="bgg" x1="0" y1="0" x2="900" y2="900" gradientUnits="userSpaceOnUse"> 
  
 <stop offset="0%" stop-color="dodgerblue"/>
 <stop offset="52%" stop-color="white">
     <animate 
            attributeName="offset" 
            values="100%;0%;100%" 
            dur="4s" 
            repeatCount="indefinite">
     </animate> 
    </stop>  
    <stop offset="100%" stop-color="gold">
        <animate 
            attributeName="offset" 
            values="100%;50%;100%" 
            dur="4s" 
            repeatCount="indefinite">
  </animate> 
    </stop> 
</linearGradient>
</defs>

<rect x="50" y="50" width="50%" height="50%" rx="5%"  fill="url(#bgg)" />
</svg> 

也尝试使用 gradientUnits =" objectBoundingBox "

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
      width="50%" height="50%" viewBox="0 0 900 900" >  

 <defs>
<linearGradient id="bgg" x1="0%" y1="0%" x2="100%" y2="100%" gradientUnits="objectBoundingBox"> 
  
 <stop offset="0%" stop-color="dodgerblue"/>
 <stop offset="52%" stop-color="white">
    <animate 
            attributeName="offset" 
            values="100%;0%;100%" 
            dur="4s" 
            repeatCount="indefinite">
    </animate> 
    </stop>  
    <stop offset="100%" stop-color="gold">
        <animate 
            attributeName="offset" 
            values="100%;50%;100%" 
            dur="4s" 
            repeatCount="indefinite">
  </animate> 
    </stop> 
</linearGradient>
</defs>

<rect x="50" y="50" width="50%" height="50%" rx="5%"  fill="url(#bgg)" />
</svg> 

此问题的任何解决方案都适用于:SVGcssjavascript

一个解决方案是使用浮点数而不是百分比,即 values="1;0;1" 而不是 values="100%;0%;100%"

svg{border:1px solid}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
      width="50%" height="50%" viewBox="0 0 900 900" >  

 <defs>
<linearGradient id="bgg" x1="0" y1="0" x2="50%" y2="50%" gradientUnits="userSpaceOnUse"> 
  
 <stop offset="0" stop-color="dodgerblue"/>
 <stop offset=".52" stop-color="white">
     <animate 
            attributeName="offset" 
            values="1;0;1" 
            dur="4s" 
            repeatCount="indefinite">
     </animate>
    </stop>  
    <stop offset="1" stop-color="gold">
        <animate 
            attributeName="offset" 
            values="1;.5;1" 
            dur="4s" 
            repeatCount="indefinite">
  </animate>
    </stop> 
</linearGradient>
</defs>

<rect x="50" y="50" width="50%" height="50%" rx="5%"  fill="url(#bgg)" />
</svg> 

您可以随时使用 javascript 来做到这一点:

requestAnimationFrame(animateOffsets);

// if this function called as callback of requestAnimationFrame, 
// so there are first argument is the time from beginning from scene start
function animateOffsets(t) { 
  requestAnimationFrame(animateOffsets);
  t = t%5000/5000; // will change from 0 to 1 (5 sec) 
  t = Math.sin(t*Math.PI*2); // will change from -1 to 1 
  stop1.setAttribute('offset', `${50 + t*50}%`);
}
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
     xmlns:xlink="http://www.w3.org/1999/xlink"
    width="50%" height="50%" viewBox="0 0 900 900" >  
 <defs>
  <linearGradient id="bgg" x1="0" y1="0" x2="60%" y2="60%" gradientUnits="userSpaceOnUse"> 
    <stop offset="0%" stop-color="dodgerblue"/>
    <stop offset="50%" stop-color="white" id="stop1"/> 
    <stop offset="100%" stop-color="gold"/> 
  </linearGradient>
</defs>

<rect x="50" y="50" width="50%" height="50%" rx="5%"  fill="url(#bgg)" />
</svg>

这里有一个 CSS 的想法,只有在你可以依靠两个渐变和一个 translation/opacity 动画来近似它的地方。我还考虑了一点模糊效果,以便在渐变之间有更好的过渡。

.box {
  border-radius:20px;
  width:200px;
  height:200px;
  position:relative;
  z-index:0;
  overflow:hidden;
}
.box:before,
.box:after{
  content:"";
  position:absolute;
  bottom:0;
  right:0;
  width:220%;
  height:220%;
  animation:translate 2s infinite linear alternate;
}
.box:after {
  background:
    linear-gradient(to bottom right,dodgerblue 0%,white 40%,gold 60%);
  animation-name:translate,show;
  opacity:0;
}
.box:before {
  background:
    linear-gradient(to bottom right,dodgerblue,white 50%,gold 50%);
  animation-name:translate,fade;
}

@keyframes translate{
  from {
    transform:translate(48%,48%);
  }
}
@keyframes show{
  30%,85% {
    opacity:1;
  }
}
@keyframes fade{
  30%,85% {
    filter:blur(8px);
  }
}
<div class="box">

</div>

渐变属性offset动画作为背景图

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
 width="50%" height="50%"      viewBox="0 0 900 900" >  

 
<linearGradient id="bgg" x1="479" y1="-345" x2="479" y2="853" gradientUnits="userSpaceOnUse"> 
    <stop offset="0%" stop-color="#fff">
        <animate 
            attributeName="offset" 
            values="0;1;1;0;0" 
            dur="5s" 
            repeatCount="indefinite"
        ></animate>
    </stop>
    <stop offset="100%" stop-color="gold">
        <animate 
            attributeName="offset" 
            values="0;1;1;0;0" 
            dur="5s" 
            repeatCount="indefinite"
        ></animate> 
    </stop>
</linearGradient>
<rect x="-45" y="0" width="70%" height="70%" rx="5%"  fill="#ACA900" />

<rect x="65" y="80" width="50%" height="50%" rx="5%"  fill="url(#bgg)" /> 
<image x="30" y="100" xlink:href="https://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg" width="50%" height="50%" />

</svg>

径向渐变效果

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
 width="50%" height="50%"      viewBox="0 0 900 900" >  
 
<radialGradient id="myRadial"
           fx="50%" fy="50%" r="80%">
          
        
    <stop offset="0%" stop-color="gold">
        <animate 
            attributeName="offset" 
            values="0;1.3;0" 
            dur="5s" 
            repeatCount="indefinite"
        ></animate>
    </stop>
    <stop offset="100%" stop-color="#EDEDED">
        <animate 
            attributeName="offset" 
            values="0;1.3;1.3;0;0" 
            dur="5s" 
            repeatCount="indefinite"
        ></animate> 
    </stop>
</radialGradient> 
<rect x="0" y="0" width="70%" height="70%" rx="5%"  fill="#ACC400" />


<rect x="85" y="80" width="50%" height="50%" rx="5%"  fill="url(#myRadial)" /> 


</svg>