Reputation: 384
Hey I display on your website a lot of business icons. I wanted to add cool animation related to them. I thought about icons staying gray until you hover them. Then they slowly became colored. First I did this effect with filter: grayscale(100%)
. But then the icons have different shades of gray that looks bad. Then I found a svg filter as shown below. Unfortunately I have no idea how to animate a transition effect for this filter. So I'm looking for help to make this animation working or another way to achieve such effect.
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" />
Upvotes: 3
Views: 8390
Reputation: 101800
Here is one way to achieve the effect you want.
I'm using two copies of the image. The grey one on the bottom. And an unfiltered one on top that fades in when you hover.
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>
Upvotes: 2
Reputation: 183
Animating the css filter tag is unreliable at best and should be avoided. There are other ways of animating SVG filters though so have no fear
Before I get started I would like to point out a flaw in your code which is not relevant to the solution but hopefully you can learn from it:
You have set your SVG to position: absolute;
and given it a size so it renders on top of other content. This is confusing to the ::hover
pseudo selector. Add the visibility: hidden;
style to the SVG to eliminate the flickering
Now on to the solution. There are many many ways of animating elements in HTML. The most common are javascript/jQuery and CSS animations/transitions. In almost every case CSS animations and transitions should be enough but there are some CSS properties which are not supported and will instantly change rather than transition. In this case fortunately we can make use of SVG animations
SVG animations allow us to change an SVG filter's properties. Before we do that we should simplify your SVG filter's code so we can animate a single property.
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" />
If you run the above code you should get a grey display. We created this by using a color matrix. We set the red, green and blue components based on the pixel's alpha property.
Now we can add an SVG animation
$('#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" />
An SVG animation must be declared within another definition (in this case inside a filter element that we wish to animate). It has the following properties
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
If we access the animations DOM object we can trigger the animation by calling its beginElement method. To end the animation call the endElement method. By setting fill="freeze"
We tell the animation to stop at the end of the duration rather than reverting the filter to its initial properties.
Here is the full code to implement the animation fade in and the animation fade out
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" />
PLEASE NOTE: I removed the from property of the animations and the endElement method call so that if you mouse out of the image while it is fading it will not jump. I also added a border to the image so you can see when you mouse over it
I found all of this information on the blog post below https://satreth.blogspot.co.za/2013/01/animating-svg-filters.html
Good luck
Upvotes: 14