【问题标题】:Animate/Transitions svg filter on image element图像元素上的动画/过渡 svg 过滤器
【发布时间】:2023-04-04 07:39:02
【问题描述】:

嘿,我在您的网站上显示了很多商业图标。我想添加与它们相关的很酷的动画。我考虑过图标保持灰色,直到您将它们悬停。然后他们慢慢地变成了彩色。首先我用filter: grayscale(100%) 做了这个效果。但是这些图标有不同的灰色阴影,看起来很糟糕。然后我找到了一个 svg 过滤器,如下所示。不幸的是,我不知道如何为这个过滤器设置动画过渡效果。因此,我正在寻求帮助以使此动画正常工作或以其他方式实现这种效果。

img {
  -webkit-filter: url(#gray-filter);
  filter: url(#gray-filter);
  transition: filter 2s;
  -webkit-transition: filter 2s;
}
img:hover {
  -webkit-filter: none;
  filter: none;
}
<svg style="position: absolute; width: 140px; height: 140px;">
  <defs>
    <filter id="gray-filter">
      <feColorMatrix type="luminanceToAlpha" result="L2A"></feColorMatrix>
      <feFlood flood-color="#b3b4bd" result="colorfield"></feFlood>
      <feBlend mode="multiply" in="L2A" in2="colorfield"></feBlend>
      <feComposite operator="in" in2="SourceGraphic"></feComposite>
    </filter>
  </defs>
</svg>
<img src="http://iconshow.me/media/images/logo/brand-logo-icon/png/128/cocacola-128.png" />

【问题讨论】:

  • 过滤器打开或关闭。当它被应用到这样的 HTML 元素时,你不能对它的一部分进行动画处理。

标签: css svg css-transitions css-animations transition


【解决方案1】:

动画css过滤标签充其量是不可靠的,应该避免。还有其他动画 SVG 过滤器的方法,所以不用担心


在我开始之前,我想指出你的代码中的一个缺陷,它与解决方案无关,但希望你能从中吸取教训:

您已将 SVG 设置为 position: absolute; 并为其指定大小,以便在其他内容之上呈现。这让::hover 伪选择器感到困惑。在 SVG 中添加visibility: hidden; 样式以消除闪烁


现在讨论解决方案。在 HTML 中有很多方法可以为元素设置动画。最常见的是 javascript/jQuery 和 CSS 动画/过渡。几乎在所有情况下,CSS 动画和过渡都应该足够了,但是有些 CSS 属性不受支持,它们会立即更改而不是过渡。在这种情况下,幸运的是我们可以使用 SVG 动画

SVG 动画允许我们更改 SVG 过滤器的属性。在我们这样做之前,我们应该简化您的 SVG 过滤器的代码,以便我们可以为单个属性设置动画。

img {
  -webkit-filter: url(#gray-filter);
  filter: url(#gray-filter);
}
<svg style="position: absolute; width: 128px; height: 128px; visibility: hidden;">
  <defs>
    <filter id="gray-filter">
      <feColorMatrix type="matrix" values="0 0 0 0.6 0  0 0 0 0.6 0  0 0 0 0.6 0  0 0 0 1 0"></feColorMatrix>
    </filter>
  </defs>
</svg>
<img src="http://iconshow.me/media/images/logo/brand-logo-icon/png/128/cocacola-128.png" />

如果你运行上面的代码,你应该得到一个灰色的显示。我们通过使用颜色矩阵来创建它。我们根据像素的 alpha 属性设置红绿蓝分量。

现在我们可以添加 SVG 动画了

$('#my-img').on('click',function(oEvent) {
  $('#gray-filter-anim-in')[0].beginElement();
});
#my-img {
  -webkit-filter: url(#gray-filter);
  filter: url(#gray-filter);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg style="position: absolute; width: 128px; height: 128px; visibility: hidden;">
  <defs>
    <filter id="gray-filter">
      <feColorMatrix type="matrix" values="0 0 0 0.5 0  0 0 0 0.5 0  0 0 0 0.5 0  0 0 0 1 0">
        <animate id="gray-filter-anim-in"  attributeName="values" attributeType="XML" begin="indefinite" dur="2" end="indefinite" from="0 0 0 0.5 0  0 0 0 0.5 0  0 0 0 0.5 0  0 0 0 1 0" to="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0" fill="freeze" />
      </feColorMatrix>
    </filter>
  </defs>
</svg>
<img id="my-img" src="http://iconshow.me/media/images/logo/brand-logo-icon/png/128/cocacola-128.png" />

SVG 动画必须在另一个定义中声明(在这种情况下,在我们希望动画的过滤器元素中)。它具有以下属性

attributeName = The property name on the filter that will be changing
attributeType = "XML"
begin         = The time offset until the animation begins. Indefinite stops it from triggering automatically so we can trigger it
end           = The time offset until the animation ends
dur           = The time duration the animation will run for. Default unit is seconds
from          = The value of the filter's property at the start of the animation
to            = The value of the filter's property at the end of the animation

如果我们访问动画 DOM 对象,我们可以通过调用其 beginElement 方法来触发动画。要结束动画,请调用 endElement 方法。通过设置fill="freeze",我们告诉动画在持续时间结束时停止,而不是将过滤器恢复为其初始属性。

这里是实现动画淡入淡出的完整代码

var fFadeIn = function(oEvent) {
  document.getElementById('gray-filter-anim-in').beginElement();
};

var fFadeOut = function(oEvent) {
  document.getElementById('gray-filter-anim-out').beginElement();
};

$('#my-img').hover(fFadeIn,fFadeOut);
#my-img {
  -webkit-filter: url(#gray-filter);
  filter: url(#gray-filter);
  border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg style="position: absolute; width: 128px; height: 128px; visibility: hidden;">
  <defs>
    <filter id="gray-filter">
      <feColorMatrix type="matrix" values="0 0 0 0.5 0  0 0 0 0.5 0  0 0 0 0.5 0  0 0 0 1 0">
        <animate id="gray-filter-anim-in" attributeName="values" attributeType="XML" begin="indefinite" dur="0.5" end="indefinite" to="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0" fill="freeze" />
        <animate id="gray-filter-anim-out" attributeName="values" attributeType="XML" begin="indefinite" dur="0.5" end="indefinite" to="0 0 0 0.5 0  0 0 0 0.5 0  0 0 0 0.5 0  0 0 0 1 0" fill="freeze" />
      </feColorMatrix>
    </filter>
  </defs>
</svg>
<img id="my-img" src="http://iconshow.me/media/images/logo/brand-logo-icon/png/128/cocacola-128.png" />

请注意:我删除了动画的 from 属性和 endElement 方法调用,这样如果您在图像淡出时将鼠标移出,它就不会跳转。我还为图像添加了一个边框,以便您在鼠标悬停时可以看到它

我在下面的博客文章中找到了所有这些信息 https://satreth.blogspot.co.za/2013/01/animating-svg-filters.html

祝你好运

【讨论】:

    【解决方案2】:

    这是实现您想要的效果的一种方法。

    我正在使用图像的两个副本。底部灰色的那个。还有一个未过滤的顶部,当您悬停时会淡入。

    img.grey {
      -webkit-filter: url(#gray-filter);
      filter: url(#gray-filter);
      opacity: 1;
      transition: filter 2s;
      -webkit-transition: filter 2s;
    }
    
    img.real {
      opacity: 0;
      transition: opacity 2s;
      -webkit-transition: opacity 2s;
    }
    
    img.real:hover {
      opacity: 1;
      transition: opacity 2s;
      -webkit-transition: opacity 2s;
    }
    
    .fader {
      position: relative;
    }
    
    .fader img {
      position: absolute;
    }
    <svg style="position: absolute; width: 140px; height: 140px;">
      <defs>
        <filter id="gray-filter">
          <feColorMatrix type="luminanceToAlpha" result="L2A"></feColorMatrix>
          <feFlood flood-color="#b3b4bd" result="colorfield"></feFlood>
          <feBlend mode="multiply" in="L2A" in2="colorfield"></feBlend>
          <feComposite operator="in" in2="SourceGraphic"></feComposite>
        </filter>
      </defs>
    </svg>
    <div class="fader">
      <img class="grey" src="http://iconshow.me/media/images/logo/brand-logo-icon/png/128/cocacola-128.png" />
      <img class="real" src="http://iconshow.me/media/images/logo/brand-logo-icon/png/128/cocacola-128.png" />
    </div>

    【讨论】:

      猜你喜欢
      • 2012-05-16
      • 2020-01-03
      • 1970-01-01
      • 1970-01-01
      • 2015-09-17
      • 2016-03-13
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      相关资源
      最近更新 更多