带有 CSS 过渡的 SVG 过滤器

Posted

技术标签:

【中文标题】带有 CSS 过渡的 SVG 过滤器【英文标题】:SVG filter with CSS transitions 【发布时间】:2017-12-22 03:23:01 【问题描述】:

我正在使用 css 动画进行 svg 过滤。我用

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="goo">
      <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
      <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7" result="goo" />
      <feComposite in="SourceGraphic" in2="goo" operator="atop"/>
   </filter>
 </defs>
</svg>

filter:url('#goo');

用于 CSS 中的容器。

这是一个小提琴 https://codepen.io/sergey_mell/pen/MoRMwR

我陷入了下一个问题。动画似乎在某个盒子内执行(它的大小似乎取决于初始动画状态大小)。 谁能帮我避免这种情况?

【问题讨论】:

【参考方案1】:

SVG 滤镜有一个定义的“滤镜区域”,在其中应用效果。这是因为某些操作可能非常慢(例如高斯模糊),并且您通常希望限制计算它们的区域。

一个过滤器的默认过滤区域是:

x="-10%" y="-10%"  

换句话说,被过滤的元素,加上一个 10% 的边框围绕它的外部。该区域之外的任何内容都将被剪裁(并且不可见)。

解决方案是增加过滤器区域,使其包含所有 blob。因此,例如,如果我们将边距提高到 50%

<filter id="goo" x="-50%" y="-50%"  >

它现在可以正常工作了。

body
  background:white;
  background-image:url(https://i.imgur.com/d47ZIU3.jpg);
  background-size:cover;

.blobs
  filter:url('#goo');
  position:absolute;
  top:100px;
  left:200px;


@keyframes blob-left-top-anim
  0%
    transform:scale(1.1) translate(0,0);
  
  33%
    transform:scale(0.9) translate(-65px,0);
  
  62%
    transform:scale(0.7) translate(-65px,-65px);

  
  94%
    transform:scale(1.1) translate(0,0);
  


@keyframes blob-right-top-anim
  0%
    transform:scale(1.1) translate(0,0);
  
  33%
    transform:scale(0.9) translate(65px,0);
  
  64%
    transform:scale(0.7) translate(65px,-65px);
  
  96%
    transform:scale(1.1) translate(0,0);
  

@keyframes blob-left-bottom-anim
  0%
    transform:scale(1.1) translate(0,0);
  
  33%
    transform:scale(0.9) translate(-65px,0);
  
  66%
    transform:scale(0.7) translate(-65px,65px);
  
  98%
    transform:scale(1.1) translate(0,0);
  


@keyframes blob-right-bottom-anim
  0%
    transform:scale(1.1) translate(0,0);
  
  33%
    transform:scale(0.9) translate(65px,0);
  
  68%
    transform:scale(0.7) translate(65px,65px);
  
  100%
    transform:scale(1.1) translate(0,0);
  

.blob
  position:absolute;
  background:#e97b7a;
  left:50%;
  top:50%;
  width:100px;
  height:100px;
  line-height:100px;
  text-align:center;
  color:white;
  font-size:40px;
  border-radius:100%;
  margin-top:-50px;
  margin-left:-50px;
  animation:blob-left-top-anim cubic-bezier(0.770, 0.000, 0.175, 1.000) 4s infinite;


  
.blob:nth-child(2)
  animation-name:blob-right-top-anim;

.blob:nth-child(3)
  animation-name:blob-left-bottom-anim;

.blob:nth-child(4)
  animation-name:blob-right-bottom-anim;
<div class="blobs">
  <div class="blob">4</div>
  <div class="blob">3</div>
  <div class="blob">2</div>
  <div class="blob">1</div>
</div>

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="goo" x="-50%" y="-50%"  >
      <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
      <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 18 -7" result="goo" />
      <feComposite in="SourceGraphic" in2="goo" operator="atop"/>
  	</filter>
  </defs>
</svg>

【讨论】:

【参考方案2】:

我实际上是通过将 width / height 设置为 .blobs 容器使其工作:

.blobs
  filter:url('#goo');
  position:absolute;
  top:100px;
  left:200px;
  width: 500px;
  height: 500px;

您可能会找到所需的最大尺寸并将其设置为该尺寸而不是 500。

【讨论】:

感谢您的帮助和快速解答!。我也找到了那个解决方案。但是,这对我来说似乎不太好,因为我不知道容器的大小,所以设置一些非常大的值或用容器覆盖整个身体似乎不太好......【参考方案3】:

如果您没有明确调整替换元素(img、svg 等)的大小,那么浏览器会为其提供 300 像素 x 150 像素(或接近的值)的默认大小。如果您不知道大小,那么如果您需要精确的像素,则需要通过 javascript 设置它,或者如果您希望它填充其包含的元素,则需要 100%、100%。

【讨论】:

以上是关于带有 CSS 过渡的 SVG 过滤器的主要内容,如果未能解决你的问题,请参考以下文章

Firefox 中的 SVG 过滤器转换

应用 CSS 过滤器时,内联 SVG 在 iOS 和 Safari 中消失

CSS 中 SVG 过滤器的奇怪错误

如何通过 CSS 将阴影过滤器应用于 SVG 特定元素/路径

如何通过 CSS 将阴影过滤器应用于 SVG 特定元素/路径

如何在 SVG 中制作插入阴影