Jump to content
Search Community

Prevent GSAP from transforming my transforms into matrix()

katerlouis 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

I came up with a way to tween a centered, fixed element out of view without "dead pixels". So when the animation starts you can immediately see it.

 

var tl = TweenMax.fromTo(".box", 2, 
	{ transform: "translateY(50vh) translateY(50%)" },
	{ transform: "translateY(-50vh) translateY(-50%)" }
);

 

For some context: http://dumbo.design/airberlin – scroll to the first "chapter intro" > the laptop mockup (Wanted to show you guys the site when it's truly finished, argh) – 75% percent of the time it works as intended. But sometimes the elements don't scroll out of view anymore, in neither direction. It feels like the `translateY(50%)` is being dropped / ignored or something.

 

Honestly, .. I am kinda afraid by the matrix(), since I cannot decipher what is happening. 

I feel like the bug wouldn't occur when I could force GSAP to keep the transform-string as is and only animate the numbers inside it. Or at least I would know that the issue is coming from somewhere else.

 

I played around with `force3D: false`, which didn't prevent matrix()

 

 

[EDIT]

just realized: the tween in the pen also seems to ignore the second `translateY`

 

Could you guys shed light into the matter for me? I really am confused on how GSAP handles transforms.

 

 

[EDIT2]

If you want to see the bug; apparently it happens more on smaller (mobile) viewports than on desktop. I couldn't reproduce it in Mac OS X latest Chrome so far.

See the Pen ELZpMY by katerlouis (@katerlouis) on CodePen

Link to comment
Share on other sites

5 hours ago, kreativzirkel said:

just realized: the tween in the pen also seems to ignore the second `translateY`

 

Assuming by this you mean you wish to use a percentage transform and have the percent based on the parent height not the box itself you could perhaps do it like this.

 

This calculates a ratio to multiply the transform by based on the item and parents height.

var transformRatio = $('.div').height()/$('.box').height(),
	 tl = TweenMax.fromTo(".box", 2, 
	 { yPercent: 50 * transformRatio},
	 { yPercent: -50 * transformRatio}
	 );

$("button").on("click", function() {
	tl.play(0);
})

 

yPercent will also animate the Y translate value directly  instead of calculating it in the matrix I believe.

 

<div class="box" style="transform: translate(0%, -262.727%) matrix(1, 0, 0, 1, 0, 0);"></div>

...from browser tools

 

 

 

See the Pen deNQRP by Visual-Q (@Visual-Q) on CodePen

 

If you want the item to start and end off screen or outside the parents bounds append code to:

 

var transformRatio = $('.div').height()/$('.box').height(),
	 tl = TweenMax.fromTo(".box", 2, 
	 { yPercent: 50 * transformRatio + 50},
	 { yPercent: -50 * transformRatio - 50}
	 );

$("button").on("click", function() {
	tl.play(0);
})

 

  • Like 2
Link to comment
Share on other sites

9 hours ago, kreativzirkel said:

Honestly, .. I am kinda afraid by the matrix(), since I cannot decipher what is happening. 

 

It's not too confusing as long as rotation is not involved. It uses skew and scale. :shock:

 

SVG and canvas could be a little different because the transform origin might be part of the matrix.

 

matrix(a, b, c, d, tx, ty);

 

U5B2wR3.jpg

 

But yeah, it looks like a possible bug. GSAP doesn't seem to handle translate as a percentage correctly. Compare it to setting the transform with jQuery. Definitely something @GreenSock should look at to confirm.

 

See the Pen rvjPbd by osublake (@osublake) on CodePen

 

 

  • Like 4
Link to comment
Share on other sites


@Visual-Q
Your solution would probably work, but also would require recalculation if the elements ratio changes. This isn't rare when looking at responsive images with art direction. Keeping those scenarios synchronized in JS and CSS is easy to forget. As much as I love GSAP; when it comes to changing stuff by breakpoints, CSS is reigning king of the hill for me. 

 

Since I feel confident to use custom css properties (css vars) in live projects, I quite often end up tweening a `--progress` for instance, and let css react to that value. But the whole responsive animation thing is something for another thread 8)

 

The main question remains: Is there a way to tell GSAP to leave the string as is and only tween the numbers? 

 

Link to comment
Share on other sites

11 hours ago, kreativzirkel said:

Your solution would probably work, but also would require recalculation if the elements ratio changes.

 

That's correct if the ratio changes  (i.e. on screen resize) the ratio would have to be recalculated, you could probably pass the Ytranslate calculations as a function with the modifiers plugin to maintain a "live" ratio to the screen size.

https://greensock.com/modifiersPlugin

 

11 hours ago, kreativzirkel said:

The main question remains: Is there a way to tell GSAP to leave the string as is and only tween the numbers? 

 

I've never used it but if you wanted to animate the values of the transform string directly I think you could use the attribute plugin.

https://greensock.com/AttrPlugin

Link to comment
Share on other sites

One of the fundamental benefits GSAP delivers is consistency in transforms' order-of-operation and being able to query those values at any given time. Like "what's the rotation right NOW?" (even if it's partway through an animation). Since CSS transforms can be chained infinitely and they're all shoved into one property, that's virtually impossible with raw CSS. Consequently, GSAP can't just pass through whatever string you feed into the transform. 

 

For example: "rotate(20deg) translate(50% 10%) scale(2) translateX(20px) skewX(10deg)" - what's the "x" in that exactly? Hm. All of those values ultimately get combined into a matrix() or matrix3d() by the browser anyway (which, by the way, are ALWAYS px-based). GSAP interprets that matrix data and populates the x/y/scaleX/scaleY/rotation/... accordingly. Again, this can be a huge convenience. But it also makes it tough to accommodate relative values like % and vw/vh. For %-based stuff, that's why GSAP offers xPercent and yPercent. There's currently no ideal solution for vw/vh but those are typically pretty easy to just convert on your own (see 

for a function that'll do it for you). 

//converts viewport units to pixels (like "50vw" or "20vh" into pixels)
function toPX(value) {
    return parseFloat(value) / 100 * (/vh/gi.test(value) ? window.innerHeight : window.innerWidth);
}

//then, in your tween:
TweenMax.to(... {x:toPX("50vw"), y:toPX("20vw")});

 

In order to work around browser issues like Firefox not reporting transforms correctly that weren't in a visible element, GSAP automatically applies string-based transforms to a proxy <div> internally but since your example uses values that are relative to the element's own width/height, it was failing (that proxy <div> had a width/height of 0). I applied a fix in the upcoming 1.20.5 release which you can preview (uncompressed) here: 

https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/TweenMax-latest-beta.js

 

So that should solve the bug in Blakes reduced test case. 

 

If you need to apply string-based transforms that are vw/vh based, I'd recommend using the conversion function I mentioned above and then in an onComplete you could just element.style.transform = "your values" so that it remains responsive and doesn't get px-based. Does that help? 

 

  • Like 4
Link to comment
Share on other sites

I'm a little lost on this one too Jack. I see how the function works and how to apply it to the tween. but I'm not understanding your suggestion for making it responsive using an onComplete:

 

20 hours ago, GreenSock said:

If you need to apply string-based transforms that are vw/vh based, I'd recommend using the conversion function I mentioned above and then in an onComplete you could just element.style.transform = "your values" so that it remains responsive and doesn't get px-based. Does that help?

 

Link to comment
Share on other sites

Let's say you animate to "50vw", but you use my conversion function which basically turns that into something like "845" (or whatever px). Great, it'll run exactly as you'd expect...but then what if the user resizes their browser to be twice as wide? The element won't adjust dynamically because the value is px-based (no longer tied to the window's width). So if you need that functionality, it'd be as simple as:

TweenMax.to(el, 1, {x:toPX("50vw"), onComplete:function() {
    el.style.transform = "translateX(50vw)"; 
}});

 

Or, if you've got other transforms in there that you want to keep, you could do this in the onComplete:

TweenMax.set(el, {x:0});
el.style.transform = "translateX(50vw) " + el.style.transform; //results in "translateX(50vw) matrix(...)"

 

  • Like 3
Link to comment
Share on other sites

Okay, I got it now, too–

 

The positive stuff that GSAP does for transforms unfortunately makes things more complicated in my case :)

I'm gonna stay persistent with my question 8) :

 

is there a way to tell GSAP to do the same with the "transform" property as it would do any other generic property?

 

This pen shows GSAP handles the string (at least the string I want to use) perfectly: 

 

(I used roundProps only for visual convenience; the actual tween wouldn't get rounded, of course)

See the Pen ELWBqz by katerlouis (@katerlouis) on CodePen

 

Link to comment
Share on other sites

I'm not familiar with Vue but I can see where you're going. I don't think there's anyway gsap can extract and animate the value in your string the way you're doing it but perhaps you can animate just the value (i.e.-50) itself and insert it into an inline style that way. 

 

<div style="transform:translateY({{ string }} + vh) translateY({{ string }} + %)"></div>

 

Note I know the syntax will be wrong I'm not familiar with Vue so it's just a wild guess.

 

On another note is it possible to apply 2 translate values in css that way? I think you would have to precaclulate the combined value or maybe there's a way to do it in a css calc.

 

Then again maybe you can use the gsap attribute plugin?

https://greensock.com/AttrPlugin

Link to comment
Share on other sites

5 hours ago, kreativzirkel said:

is there a way to tell GSAP to do the same with the "transform" property as it would do any other generic property?

 

 

Short answer: sure, just animate a string on a proxy object and plug that in manually via an onUpdate to element.style.transform (basically exactly what @Visual-Q suggested). This will only work if the starting/ending strings have exactly the same quantity of numbers in the same spots.

 

Long answer: no, this isn't feasible on the "real" transform. To illustrate why, it'd probably help most to just give you an example: 

 

How would you interpolate halfway between "rotate(45deg) translate(50vw, 20vh) scale(2)" and "translate(25px, 80px)"? And remember, the browser always reports the current (computed) transform state as a matrix() or matrix3d() which are px-based. So a to() tween must grab the current value, thus how would you interpolate between these two values?: "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)" and "rotate(30deg) translate(50vw, 20vh)"? What's exactly 20% between those two states? See the problem? 

 

Furthermore, even in your example with animating between two strings that match perfectly (only the numbers are different in the start/end values), what would GSAP report as _gsTransform.x, _gsTransform.y, etc. during the tween? What happens if you need a separate tween that starts halfway into that one, but affects "rotation" or "scale"? Hmmmm. Things get VERY complex quickly. 

 

You may think it's silly that GSAP doesn't just slap the string onto the transform but there's a ton that goes into the proper management of transforms that most people never even realize, especially because GSAP makes it "just work". The only thing that's not super-simple right now is the vw/vh stuff, but %-based things are handled by xPercent/yPercent special properties but maybe you could tap into CSS variables for that. Remember, GSAP can even animate CSS variables. 

 

https://greensock.com/css-variables 

  • Like 3
Link to comment
Share on other sites

6 hours ago, kreativzirkel said:

The positive stuff that GSAP does for transforms unfortunately makes things more complicated in my case :)

 

I tend to think that if you get it set up right the way GSAP handles transforms shouldn't present a problem. That's only a  guess though, since I have no idea what the original bug is.

 

If transforms are causing you difficulties though what about adjusting your css and positioning your object absolutely and animating top, left values instead of transforms. If they animated as percentage values they would be relative to the parent and responsive.

  • Like 3
Link to comment
Share on other sites

2 hours ago, Visual-Q said:

I'm not familiar with Vue but I can see where you're going.

 

I only used Vue in the pen to make it more of a habit. Ignore Vue in this case– what you were illustrating isn't what I'm going for :)

I really just wanted to avoid the proxy-object- or css-var- or or or route :D

 

37 minutes ago, Visual-Q said:

If transforms are causing you difficulties though what about adjusting your css and positioning your object absolutely and animating top, left values instead of transforms. If they animated as percentage values they would be relative to the parent and responsive.

 

The elements are already positioned absolutely (fixed to be more precise) – my experiences with tweening top/right/bottom/left haven't been too good. Maybe have a look at the actual feature I'm having issues with, the two laptops- and phonemockup; it's pretty complex: http://dumbo.design/airberlin  (please don't open in Safari.. I'm currently having the weirdest bug ever in Safari, insanely glitched in every aspect... I mean.. literally glitched)

 

1 hour ago, GreenSock said:

You may think it's silly that GSAP doesn't just slap the string onto the transform but there's a ton that goes into the proper management of transforms that most people never even realize, especially because GSAP makes it "just work".

 

I don't think that. I think it's awesome. And I understand that these things are necessary. I was just hoping that there is some kind of a "switch" that disables all this fancy cool stuff for this one Tween. 

 

 

Now I know what I'm asking is impossible and can move on

responsiveness in general is still a topic you'll hear me whine about 8)

 

 

If your thinking now: "Dude.. you could've just did either of all the solutions at hand and would've saved way more time than trying to dig for the 'cleanest' solution" – Besides that's just the way I'm wired, I really enjoy this digging; learning the little details, caveats, gotchas, hickups; figuring out what's going on under the hood; getting more puzzle pieces to see the whole picture– The more I truly understand, the more tools I have to solve trickier stuff.

  • Like 1
Link to comment
Share on other sites

Dude.. you could've just used CSS vars like I showed you. ?

 

Here's a piece of your puzzle. GSAP works with objects. An element's style is an object. Therefore, GSAP can animate the style.

 

var tl = TweenMax.fromTo(box.style, 2, 
  { transform: "translateY(50vh) translateY(50%)" },
  { transform: "translateY(-50vh) translateY(-50%)" }
);

 

 

7 hours ago, kreativzirkel said:

responsiveness in general is still a topic you'll hear me whine about 8)

 

 

I think people overthink responsive design, especially when it comes to animations. It's no secret that using x/y is better than left/top, but some people don't care because they want to use relative units like %. They are so focused on how an animation behaves during a screen resize, that they are willing to look past that.

 

NEWS FLASH: That only makes your animation responsive in size. Animations have a time component, and speed = distance / time, so an animation will move much slower on a phone than it does on a desktop. 

 

Guess what? People don't resize their screens to test out the responsiveness of a site. If a person resizes their screen, it's usually because they need to adjust how the content is being displayed. Don't take my word for it. Start tracking resize events and the window size. If there's a problem with your layout, you'll see it in the percentage of users that resize their screen.

 

  • Like 5
Link to comment
Share on other sites

11 hours ago, OSUblake said:

I think people overthink responsive design, especially when it comes to animations. It's no secret that using x/y is better than left/top, but some people don't care because they want to use relative units like %. They are so focused on how an animation behaves during a screen resize, that they are willing to look past that.

 

I don't care that much how animations behave during an active resize, however, if the animation endpoint isn't responsive then items can end up out of place which is a problem. You can always reset the position at the end of animations if necessary I guess, but a responsive solution from the start is desirable in my opinion. I guess there's no perfect solution since any "live" recalculations of transforms during screen size changes would add it's own overhead and probably negate the performance gains.

Link to comment
Share on other sites

12 hours ago, OSUblake said:

That only makes your animation responsive in size. Animations have a time component, and speed = distance / time, so an animation will move much slower on a phone than it does on a desktop. 

 

This is exactly what I'm referring to. 

 

12 hours ago, OSUblake said:

Guess what? People don't resize their screens to test out the responsiveness of a site.

 

But they rotate their handheld devices:

You are on the toilet, checking this fresh new site on your iPad, in portrait mode, of course– And you think: "Wow, how cool is this site? Gotta show that to Erica!"

After the important business is concluded, you pinch the iPad under your armpit like a pro and wash your hands. Boom! The accelerometer tells Safari to go Landscape mode => resize!

Sheer excitement over these astonishing animations make you run to Ericas desk, swinging and shaking the tablet extensively. You stuff the device in Ericas face, who couldn't hold back a little scream of amazement. She grabs it like a fresh Pizza and rotates it to Landscape mode, because.. well, she's Erica. After she fainted and fell to the floor, you quickly pick up the device, looking for damage. Phew! Nothing happened. You step over Erica to get back at your desk, put the tablet in it's stand (in Landscape, of course) and go into split-view to write a mass-text and -email to everybody you did, do and will ever know, about the website that changed your life and finally brought peace to the world–

 

 

Okay, okay– I overexaggerated a tiny bit. But just watch how people use their tablets these days. Especially those people who use it as their main device.

We can't escape it. Websites get resized in reality. The likelihood increases on these hip new things called "one-pager", or, like in my case, on single page applications; or just on pages you stick around for quite some time. "Man, this article is looong, I read on later.."

 

And this is just tablets, there are so many real life occasions where open websites get resized;

– most smartphone browsers show / hide / shrink their UI on scroll

– unplug the big monitor from the laptop, Chrome goes from 1920 to 1440 width

– cool photos on a page, you want to drag them into a folder, you resize to make room

– browser into or out of fullscreen mode

– new Safari window, you CMD-Click a bunch of links > the tab row comes in

 

You see why I phrased "get resized" – Even if users rarely resize the browser in terms of actively dragging the corners, usage alone may result in resize.

 

Especially on a show-case site like my example, you probably have only one shot to impress the user. I really don't want to know how much exactly the impression changes when he/she feels the need to refresh the page in order to get a "pristine animation" –

 

"Look at this! .. Oh wait– I don't know why it did that, .. strange, it worked a few minutes ago;" – you impressed somebody so much that he felt the need to share his excitement. Then you make him look like a fool, which makes you the biggest fool of all.

 

Everytime I witness this scenario on one of my sites, a little part of me dies.

And I deeply hope the day I stop trying to avoid this is beyond my 70th birthday.

 

 

(I should stop chillin in these forums while commuting :FF)

Link to comment
Share on other sites

4 minutes ago, kreativzirkel said:

Especially on a show-case site like my example, you probably only have one shot to impress the user. I really don't want to know how much exactly the impression changes when the user feels the need to refresh the page in order to get a "pristine look" –

 

I agree when a page breaks, it breaks. Saying "oh it wasn't meant to resized, just refresh it and it will look right", won't get you any applause.

Link to comment
Share on other sites

14 hours ago, kreativzirkel said:

Especially on a show-case site like my example, you probably have only one shot to impress the user. I really don't want to know how much exactly the impression changes when he/she feels the need to refresh the page in order to get a "pristine animation" –

 

14 hours ago, Visual-Q said:

I agree when a page breaks, it breaks. Saying "oh it wasn't meant to resized, just refresh it and it will look right", won't get you any applause.

 

Strange. I don't remember saying that you should force the user to refresh the page.

 

Perhaps my post wasn't clear. My point is this, if your layout changes, then you may need to update your animations. Any potential performance hit will be unnoticeable for the most part. A screen resize invalidates pretty much everything, so elements are going to be jumping around whether they're being animated or not.

 

A simple demo reacting to resize and media change events. The color changes on media changes.

 

See the Pen jLLqbY by osublake (@osublake) on CodePen

 

 

 

 

Link to comment
Share on other sites

Weird; I totally read your post as "guys, IF you would make animations responsive, you had to do so much more than this and that, and that's not worth it, since people just don't resize their browsers" – Glad I misunderstood it ;)

 

Anyway;

Pandora's Box has been opened, so let's continue this in separate thread.

 

https://greensock.com/forums/topic/18280-truly-responsive-animations/

Link to comment
Share on other sites

9 hours ago, OSUblake said:

Strange. I don't remember saying that you should force the user to refresh the page.

 

You didn't I was responding to @kreativzirkel's post. 

 

21 hours ago, kreativzirkel said:

I really don't want to know how much exactly the impression changes when he/she feels the need to refresh the page in order to get a "pristine animation" –

 

 

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