Jump to content


Scrolltrigger broken when starting at translateY(-50%)

Go to solution Solved by akapowl,

Recommended Posts

Scrolltrigger does not work when trying to do a scrub animation with an element that is positioned transform:translateY(-50%) . In the attached example -49% and -51% work as expected, but -50% stays in the same position while scrolltrigger appends translate3d(0px, 0px, 0px) to the element.


<div class="wrap">
  <div class="box1" style="transform: translate3d(0px, -36.4235px, 0px);"></div>
  <div class="box2" style="transform: translate(0%, -50%) translate3d(0px, 0px, 0px);">broken</div>
  <div class="box3" style="transform: translate3d(0px, -37.7385px, 0px);"></div>


See the Pen gOgPmpz by nategabriel (@nategabriel) on CodePen

Link to comment
Share on other sites

  • Solution

Hey @ntgbrl- welcome to the forums.


From what I understood from @GreenSock's explanation in this thread



this might be related to GSAP handling translateY(-50%) in a very specific way.




Here's two ways you could get the desired result:


1) Initially set your transforms with GSAP instead of CSS


See the Pen 397f667a79c017e90bb951f71077a993 by akapowl (@akapowl) on CodePen




or 2) Let them be set via CSS but tween on the yPercent instead of the y for that element with translateY(-50%) applied


See the Pen 714760b7fde807c2fed9bdf7416376cb by akapowl (@akapowl) on CodePen



or even a 3rd) combine both - setting the yPercent for every element with gsap and tweening on the yPercent for every element.


See the Pen 8eb4eadddb7377c93bccc5c4f1bfdc89 by akapowl (@akapowl) on CodePen


Hope this helps.


  • Like 3
  • Thanks 1
Link to comment
Share on other sites

Let the culprit from said thread chime if, if you will ;-)


@akapowl is totally right. If you want things mostly animated and reliably, not to mention performantly running go with all he said and provided.


If in your scenario -  like in mine - that isn't your priority or just not feasible here is the additional good news (also form said thread and the master mouth: ) 



But I'm glad you persisted and pointed this out, as it confirmed that the patch in 3.6.1 resolves this. Let me know if it works better for you once you swap in the beta GSAP. Seemed to work fine for me. 

 It did in my case. And 3.6.1 is out of beta also.

  • Like 1
Link to comment
Share on other sites


Fair point @iDad5 - I remembered the explanation but not the change in 3.6.1 you mentioned.


Simply updating to the latest version doesn't change the situation in the provided example though - but maybe I just misunderstood what it was you were saying, no offense.


See the Pen 1cffd7f2435629db42b9ba7783d13172 by akapowl (@akapowl) on CodePen


On a sidenote, @ntgbrl:

You are using GSAP 3.3.4 together with ScrollTrigger 3.5.1 in your demo - best keep the versions consistent.


  • Like 3
  • Thanks 1
Link to comment
Share on other sites

2 hours ago, akapowl said:

Simply updating to the latest version doesn't change the situation in the provided example though - but maybe I just misunderstood what it was you were saying, no offense.

@akapowl is correct. 


@iDad5 the issue (before 3.6.1) merely had to do with when someone doesn't follow best practices of using the component properties like x, y, xPercent, yPercent, scaleX, scaleY, etc. and instead passes in a string transform like transform: "translate(0px, -50%)". That very specific scenario has been fixed but again, I strongly recommend against ever using that syntax :)


@ntgbrl as I tried to explain in the other thread, there are TWO y-related properties that GSAP recognizes which can be COMBINED for some really cool effects - "y" and "yPercent". When parsing the CSS values you set initially, the browser reports those as PIXELS (well, a matrix() or matrix3d() which is pixel-based), so GSAP cannot know that your value was percent-based. For example, if you've got a 200px-tall box and you set transform: translateY(-50%) the browser will report that like "matrix(1, 0, 0, 1, 0, -100)" - that last number means -100px on the y axis. So GSAP must make a decision - does that belong in the "y" value or the "yPercent" value? Since it's so common for people to use -50% to center things, GSAP sees that -100px is exactly -50% of the height of the element, and assumes that should be interpreted as yPercent: -50 instead of y: -100. Either one would result in the same position technically. 




...if it interprets it as yPercent: -50, that means it'll set y to 0! That's the key here. It EITHER goes into yPercent OR y. 


When you used -49%, it didn't match that very specific scenario where it's offset by precisely half of the height in the negative direction, thus it puts it in the "y" value (thus "yPercent" is 0). 


See how it works? 


Also, do you see why it's so valuable to set your initial values directly through GSAP? It eliminates any ambiguity - you can tell it exactly where the values should go. 


Your tweens were animating the "y" value to zero, but in the case of the translateY(-50%) one, y was already 0 and yPercent was -50. So you were animating y from 0 to 0 (while yPercent stayed at -50). See why it behaved that way now? 


Hopefully that sheds light on the "why" behind not only the problem, but also why @akapowl's solutions work. The only thing I'd change about his first solution is to define BOTH components initially (y and yPercent), and whenever you use % it belongs in the yPercent (even though technically it often works the other way too):

// not as good
gsap.set('.box2', { y: "-50%" })

// best
gsap.set('.box2', { y: 0, yPercent: -50 })

But then of course you'd need to change your tweens to animate yPercent to 0 instead of y. 

  • Like 5
Link to comment
Share on other sites

@akapowl, @ntgbrl & @GreenSock - sorry, I didn't have a lot of time, but when I saw akapowl's mention of the thread and my problem it seems very similar and I thought I'd remark that my problem was fixed by the update. I didn't dig deeper but I probably should have stated clearly that my problem was solved that way but I didn't check if ntgbrl's problem was similar enough. Next time I'll try to check before posting.

  • Like 1
Link to comment
Share on other sites

@iDad5 no worries at all. It was a good excuse for me to give a more detailed explanation here. 👍

  • Like 1
Link to comment
Share on other sites

@GreenSock Thanks for explaining why the behavior is the way it is, it really help me wrap my head around the nuances of scrolltrigger.


Also, thanks to @akapowl and everyone else for the help and code recommendations


  • Like 1
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.