Jump to content


Conversion from CSS Transforms to GSAP: Significant Differences

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

Hey, guys.


I'm having some trouble moving my CSS3 animations to GSAP. I'm new to this animation library so bear with me.


I have several elements starting off-screen and dropping downwards into their final resting places. Each element has its own unique CSS transform string, containing some or all of the following: perspective, rotateX/Y/Z, and skewX/Y.


My first attempt was to use from() and have GSAP do all of the heavy lifting interpolating from a base state I defined in a JSON object to the state defined in my CSS transform strings. Unfortunately, I couldn't get any 3D transforms to occur; only the vertical translation. In other words, the elements would move but would look out of place since their final state had no rotation or skewing present.


I posted a question on SO and Jack recommended I move away from these transform strings entirely and use GSAP native animation properties. (He also pointed me to these forums.) So, I switched from, ah, from() and moved to, uh, fromTo().


I explicitly defined the initial and final states in JSON objects and handed them off to fromTo() for animation. I used my original CSS transform string values (i.e. transform: perspective(400px) rotateX(39deg) etc etc) in my GSAP state objects (i.e. 'transformPerspective': 400, 'rotation': 0, 'rotationX': 39).


Unfortunately, the end result is fairly different from the pure CSS transform version. I came up with two fiddles to demonstrate the difference:


Pure CSS: http://jsfiddle.net/nLohzgzb/4/

Pure GSAP: http://jsfiddle.net/fuoch37v/


Note that the animation itself is different (no "blowing in the wind"-type effect) and the end results aren't identical either.


I'm sure I'm just doing something wrong or missing something obvious.


Could someone point me in the right direction?



Link to comment
Share on other sites

Aha, this looks like an order-of-operation thing. Let me take a step back and explain the dilemma....


The CSS spec allows you to define a transform string with any order you want (like rotateX(), then rotateY(), then translateX(), then skewX(), or whatever) and it performs them in the order you declare. If you switch the order around, you can get drastically different results visually. This may seem really cool...but for animators, it can be an absolute mess. It's one of those "features" that sounds cool in theoretical/academic discussions, but in practical reality it wreaks havoc. 


For example, animators typically think in terms of absolutes, like "I want the x position to animate to ___" or "rotationX should end at ___". But if there's no consistency in the way things get applied, it becomes very messy to deal with because let's say you've got an element that has a bunch of transforms that include rotationX, rotationY, rotationZ, x, y, scaleX, etc. And then you want to animate it so that its scaleX is 0.5, and that's all you care about (keep the other transform components whatever they are at the time). How can you do it? Would you get the computed style and try to parse the values from the matrix3d and then create a whole new string that includes all the rotational/translation/skew values but edit only the scaleX part? Totally unrealistic. Pretty much nobody would do that. 


This is why GSAP imposes a consistent order of operation in the way it applies its transform components. You get complete independent control with perfect consistency across the board, and you don't have to try to track a bunch of values yourself manually. You just animate any component independently and GSAP ensures that things are composed into the matrix3d() in the appropriate order (the same very time). The only "down" side to this approach is that you don't get to use the native properties and impose your own (different) order for composition. 


In your particular case, you and a bunch of transforms in a string that were defined in a non-standard order, thus when you tried to recreate that using GSAP's native properties, it looked different. 


As I see it, your options are:

  1. Figure out what the component values are for GSAP's native properties to get the exact transform you're looking for. You could pass in your "transform" string to a tween (or set()) and inspect the _gsTransform object on the element which stores all of those values. (look at it in Dev Tools). 
  2. Define a "transform" string as you were before. In some very rare cases, you might notice a slight difference in the way things render which has to do with the very complex parsing/interpolation of the computed matrix3d() and busting it apart into the components (when there are multiple axis of rotation, it becomes virtually impossible to distinguish certain aspects, thus approximation is necessary).
  3. Just use CSS for those parts (but of course that means you lose the ability to control each component or the whole animation, and you can't do it on SVG elements because CSS transforms just don't work in some browsers whereas GSAP solves the issues by using JS and some wizardry). 
  • Like 1
Link to comment
Share on other sites

Hey Jack,


Thanks for the response. That makes a lot of sense.


What order does GSAP run through the transform properties? Knowing that would help, since I'd be able to fiddle with an equivalent CSS transform string in a sandbox instead of having to run through the animation for debugging.

Link to comment
Share on other sites

Here's an excerpt from the CSSPlugin docs


In regular CSS, the order that you list the transforms matters but GSAP always applies them in the same order for consistency: translation (x, y, z), then scale, then rotationX, then rotationY, then skew, then rotation (same as rotationZ) although in terms of constructing the matrix, the math is technically done in the reverse of that order.



Does that help? 

  • Like 1
Link to comment
Share on other sites

Hey Jack,


That's really helpful. When does skewing (skewX/skewY) take place?


My understanding is that if I restructure my CSS transform strings to use the GSAP order (translate X/Y/Z -> rotation X/Y/Z -> scale (and skew?)), then I should receive identical results between the two.


Let me know if I'm misinterpreting something.


I guess ultimately it doesn't matter too much -- all I'll really need is the GSAP animation properties to be right. Still, it would be nice to be able to quickly reference the CSS for the final transform state (even if it's overridden by the 3D matrix). 



Link to comment
Share on other sites

Ah, sorry I  neglected to mention skew. Here's the updated excerpt: 


... translation (x, y, z), then scale, then rotationX, then rotationY, then skew, then rotation (same as rotationZ) ...



Is that what you need? 


Again, if there's any way you can just use GSAP for all the transforms instead of CSS, I think you'll get the best results (not that it's "wrong" to use CSS). 

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.