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

Posted

技术标签:

【中文标题】Chrome 不适用于线性渐变的属性偏移动画【英文标题】:Chrome doesn’t work on the animation of the attribute offset for a linear gradient 【发布时间】:2019-11-29 13:14:48 【问题描述】:

下面是在Firefox 中运行良好的代码,但是任何尝试在Chrome 中为线性渐变的偏移属性设置动画都没有结果。

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
	       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"   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"
	       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"   rx="5%"  fill="url(#bgg)" />
</svg>	

此问题的任何解决方案都可以使用:SVG,css,javascript

【问题讨论】:

报告给 Chrome 的 bugtracker。 对纯 CSS 动画感兴趣? @Temani Afif 我期待你解决 CSS,但我对动画的确切属性很感兴趣 offset 很难做到完全相同,但我们可以这样近似:jsfiddle.net/d6kbvx1n ...我很确定我们可以做得更好,但它需要更精确的值. @Temani Afif 请在此处发布您的 CSS 解决方案。 【参考方案1】:

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

svgborder:1px solid
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
	       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"   rx="5%"  fill="url(#bgg)" />
</svg>	

【讨论】:

一个有趣的解决方案谢谢!令人惊讶的是,values =" 1; .5; 1 "gradientUnits =" userSpaceOnUse " 时有效【参考方案2】:

您可以随时使用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"
	     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"   rx="5%"  fill="url(#bgg)" />
</svg>

【讨论】:

我喜欢你使用Math.sin()这一事实。它使动画更流畅。 @enxaneta 我也喜欢在这里使用缓动函数gist.github.com/gre/1650294【参考方案3】:

这是一个仅使用 CSS 的想法,您可以依靠两个渐变和一个平移/不透明度动画来近似它。我还考虑了一点模糊效果,以便在渐变之间有更好的过渡。

.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>

【讨论】:

【参考方案4】:

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

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
	       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"   rx="5%"  fill="#ACA900" />

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

</svg>

径向渐变效果

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink"
	       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"   rx="5%"  fill="#ACC400" />


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


</svg>

【讨论】:

以上是关于Chrome 不适用于线性渐变的属性偏移动画的主要内容,如果未能解决你的问题,请参考以下文章

01超精美渐变色动态背景完整示例CSS动效实战(纯CSS与JS动效)

CSS中的渐变——线性渐变

css使用线性渐变属性没有用是怎么回事

Canvas使用渐变之-线性渐变详解

Canvas 线性渐变原理详解

Cordova 无法处理的具有线性渐变的 SVG - iOS