Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG filter with CSS transitions

I was doing and svg filter with css animation. I use

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

and

filter:url('#goo');

for container in CSS.

Here is a fiddle https://codepen.io/sergey_mell/pen/MoRMwR

And I got stuck into next issue. The animation appears to be carrying out like inside some box (it's size seems to be depend on initial animation state size). Can anybody help me to avoid this?

like image 332
Sergey Mell Avatar asked Mar 08 '23 14:03

Sergey Mell


2 Answers

SVG filters have a defined "filter region", inside which the effects are applied. This is because some operations can be very slow (eg. gaussian blur) and you generally want to limit the area over which they are calculated.

The default filter region of a filter is:

x="-10%" y="-10%" width="120%" height="120%"

In other words, the element being filtered, plus a 10% border around the outside of it. Anything outside that area will be clipped (and invisible).

The solution is to increase the filter region so that it encompasses all of your blobs. So, for example, if we increase the margin to 50%

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

it now works properly.

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%" width="200%" height="200%">
      <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>
like image 172
Paul LeBeau Avatar answered Mar 16 '23 14:03

Paul LeBeau


I actually made it work by setting a width / height to the .blobs container:

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

You can probably find out the max size you need and set it to that instead of 500.

like image 42
Ovidiu Dolha Avatar answered Mar 16 '23 14:03

Ovidiu Dolha