Jump to content
Search Community

filter animation in GSAP

Sophia test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hello all,


I have encoutered two problems with gsap.


The first one is that I want to make a filter animation with gsap, in which I may modify several css filter properties at the same time.

-webkit-filter:saturate(1) hue-rotate(0deg) brightness(1) contrast(1)) grayscale(0.5)

How can I set these filter properties in gsap timelineLite? Expecting the similiar way like transform:


And How can I get these filter properties in separately in progress ?  Expecting the similiar way like transform:


The second one is that how does gsap perform in mobile device with dozens of elements animating at the same time,maybe 30 or 40, and each element animation many have several tweens. Under this situation,which will perform better, css animation or gsap?


Any help very much appreciated!


I'm looking forward to your reply, thank you very much. :)

Link to comment
Share on other sites

Hi Sophia,


For the first question. Since version 1.18.3 (released yesterday by our beloved leader :D) you can pass complex strings to the configuration object. Jonathan jumped right away onto that an gave us a nice sample in this post:




Here's a direct link to His codepen sample


See the Pen bpKKRm by jonathan (@jonathan) on CodePen



As for getting the current value, the super secret _gsTransform is a particular object that deals with transform objects. Although I haven't dug into the CSS Plugin  in order to see an object that keeps track of the styles values, those normally are kept behind the scenes as private objects/methods, so the rule of thumb is not to rely on them because they're designed for internal use (in GSAP normally everything that starts with an underscore - at least the last time I checked). One option could be to check the element's style using the style object or jquery's css() method to get the particular style.


For the second question, GSAP always performs great. The most common performance issue comes from rendering/painting the screen. You can have 30 to 40 elements animating, but keep in mind that, regardless how new a device could be, their hardware is smaller and has more limitations than a desktop/laptop, specially phones. The mantra around here is test, test, test and then test some more. With that in mind, regardless if you're using, velocity, pixi, CSS or GSAP performance could be an issue depending on the object's size, transparency (has transparency or opacity, or not), size, property being animated (affects flow or not), is a solid element or an image, etc. As you can see is really hard to narrow it down to what tool you use, but it depends more of what you're doing and what you're animating and the end device. That's why many sites/apps have far less animations for devices than for desktops/laptops and even sometimes they don't have any animations whatsoever.

  • Like 4
Link to comment
Share on other sites

Rodrigo is right, due to new support for tweening numbers in complex strings, you can pull off some nifty filter effects.

So if you tween from


webkitFilter:"saturate(0) hue-rotate(0deg) brightness(0) contrast(0) grayscale(0.5)"




webkitFilter:"saturate(1) hue-rotate(90deg) brightness(1) contrast(1) grayscale(0)"
CSSPlugin will just tween the first number it finds in the first string (0) to the first number it finds in the second string (1) and continue to do the same for each pair in both strings.
Here is the full syntax and example (tested in Chrome, Safari and FireFox)
  var timeline = TweenMax.fromTo('#grayscale img', 2, 
                                 {webkitFilter:"saturate(0) hue-rotate(0deg) brightness(0) contrast(0) grayscale(1)",
                                 filter:"saturate(0) hue-rotate(0deg) brightness(0) contrast(0) grayscale(1)"
                                 {webkitFilter:"saturate(1) hue-rotate(90deg) brightness(1) contrast(1) grayscale(0)",
                                 filter:"saturate(1) hue-rotate(90deg) brightness(1) contrast(1) grayscale(0)"});

fork of Jonathan's demo: http://codepen.io/GreenSock/pen/BKPyJp?editors=0010



However, I want to make it clear that CSSPlugin has NO internal support specifically for css filters. It really has no idea what the brightness value or grayscale values are individually. It just knows that it is applying a big mush of a string to a -webkit-filter and filter property. This means that after you apply a string like this with multiple filter functions there really isn't a clean way to independently adjust the brightness without causing problems with satururate, contrast and the others.


So unlike transforms, there is no secret _gsFilterObject that is internally independently keeping track of each filter. The filter is just represented by a single string.


Although filter support is getting better across browsers we are still waiting for widespread adoption and most likely the removal of any prefixes before investing a ton of time into it.  Hopefully the new complex string support gives you enough flexibility to have some fun.


Special thanks to Rodrigo and Jonathan for providing great insight and demos!

  • Like 4
Link to comment
Share on other sites

Thank you all for replying me so patiently, Rodrigo and Carl.


That really help me a lot.

I have been using gsap for about a month in my new project, and I really love it and your team. You are so nice.


I tried the demo:http://codepen.io/Gr...Jp?editors=0010, but I found that the transition of blur doesn't work ,it just changed instantaneous.

var timeline = TweenMax.fromTo('#grayscale img', 2, 
                                 {webkitFilter:"blur(0) saturate(0) hue-rotate(0deg) brightness(0) contrast(0) grayscale(1)",
                                 filter:"blur(0) saturate(0) hue-rotate(0deg) brightness(0) contrast(0) grayscale(1)"
                                 {webkitFilter:"blur(5px) saturate(1) hue-rotate(90deg) brightness(1) contrast(1) grayscale(0)",
                                 filter:"blur(5px) saturate(1) hue-rotate(90deg) brightness(1) contrast(1) grayscale(0)"}); 

Should I handle the filter of blur individually ?

Link to comment
Share on other sites

Thank you, Jack.


I found that the transition of 'hue-rotate' doesn't work either, will this also be fixed in 1.18.4?


And may can I ask when you will release 1.18.4?



Best wishes to you and your team! :)

Link to comment
Share on other sites

Hello all,


I found that there is a minor bug of borderRadius in the version of 1.18.3.

I want to make a animation like this below:

var timeline = TweenMax.fromTo('#grayscale img', 10,  {borderRadius:16},{borderRadius:0}); 

The borderRadius will changed from 160 to 0, not 16 to 0. But it works well in the version of 1.18.2.


However, if I add the unit of 'px' , it works right.

var timeline = TweenMax.fromTo('#grayscale img', 10,  {borderRadius:'16px'},{borderRadius:'0px'}); 

Is it a minor bug or an update in the new version that every number should set with a unit ?


Thank you so much.

Link to comment
Share on other sites

Yes, according to my tests both of those are fixed in 1.18.4 - you can test it yourself by just linking to https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/TweenMax-latest-beta.js for TweenMax. Sorry about the glitch in 1.18.3. As for when we'll release 1.18.4, probably within the next few days. You're welcome to just revert to using 1.18.2 or use the preview of 1.18.4 (just don't link directly to that beta URL - download it, minify it, and use it on your server).

Link to comment
Share on other sites

  • 9 months later...

What's weird is that when you get the initial value from the browser, it reports it with the color as the FIRST parameter:

var div = document.querySelector("div");
div.style.filter = "drop-shadow(0px 0px 5px #f00)";
var cs = document.defaultView.getComputedStyle(div);
console.log(cs.filter); //reports drop-shadow(rgb(255, 0, 0) 0px 0px 5px)

So that was throwing things off, as GSAP was trying to tween drop-shadow(rgb(255, 0, 0) 0px 0px 5px) to "drop-shadow(0px 0px 5px #00f)", so the values didn't match up. 


Here's how you could do it with a generic value:

function alsoWorks() {
  var filter = {value:"drop-shadow(0px 0px 5px #f00)"},
      element = document.querySelectorAll('div')[0];
  TweenLite.to(filter, 1, {
    value: "drop-shadow(0px 0px 5px #00f)",
    onUpdate: function () {
      element.style.filter = filter.value;

I've also made an improvement in the next update to handle that situation better but it'd still require that you put things in the order that the browser reports them. 


Reminder: since browser support for filters is so inconsistent, GSAP doesn't "officially" support them. 

  • Like 2
Link to comment
Share on other sites

that is really strange, given that all the documentation on `drop-shadow` shows the params in that order, but overall the reason for this break makes sense. it seems like with what you have said that flipping the order now with 1.19.1 would fix the problem, but it does not. is that expected?

Link to comment
Share on other sites

No no, there's still a complexity with the string parsing and the fact that the value has "drop-shadow(" immediately followed by a color that needed a workaround which is why I mentioned the "next update" that you can preview at https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/TweenMax-latest-beta.js. The best way to handle it at the moment is to use that solution with the generic object or create a simple plugin. 

Link to comment
Share on other sites

Yep, that was a little confusing. Sorry about that - it just has to do with the onUpdate not firing for the immediateRender in that vary particular case (a fromTo() tween). The "from" vars are used under the hood to render the initial state; since your onUpdate was in the "to" vars (as it should generally be), it wasn't along for the ride on that initial render. 


I'll work around that in the next release, but in the mean time it should be as simple as adding the onUpdate to the "from" vars. 

tl.fromTo(... {onUpdate:yourFunc, ...}, {onUpdate:yourFunc, ...});


Link to comment
Share on other sites

  • 4 months later...

I have an element tweening filter to contrast(0.5) over a minute and then, based on user action during that minute might also have to tween filter to blur(3px) over just a few seconds.


I worked around this using a proxy object and creating the filter string on onUpdate.


Wondering if this is the sort of thing that making myself a plugin would be good for [1]?  Is there a plugin example more aligned with what I am describing for reference?  Thanks!








Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...