We’ve created an SVG and animated it using GreenSock in my previous tutorial,
but what if we wanted the animation to only trigger when the user scrolls past a certain point of the website?
In today’s ScrollMagic tutorial we will trigger our GreenSock animation based on the scroll position.
Here’s the final result.
1. Include ScrollMagic
Firstly we will include ScrollMagic in the html, just after the TweenMax.min.js
reference.
<script type="text/javascript" src="js/jquery.scrollmagic.min.js"></script>
I pasted the smaller version of ScrollMagic into my plugins.js
.
Download Free Toolkit
All you need to know to get started with GreenSock and ScrollMagic, in one single package. Straight into your inbox.
2. Trigger Animation In The Middle Of The Viewport
By default all animations (tweens and timelines) are triggered by ScrollMagic when the top of the triggerElement
reaches the middle of the viewport.
// Controller var controller = new ScrollMagic(); // 2. Curtain Timeline var tlCurtain = new TimelineMax(); tlCurtain.set($curtain, {yPercent: -100}) .to($curtain, 0.3, {yPercent: 0, ease:Power4.easeOut}) .to([tomatoLeft2, tomatoLeaves2, tomatoRight2, letters2, bracketRight2, bracketLeft2], 0.01, {fill: "#707070"}) .to($curtain, 0.3, {yPercent: -100, ease:Power4.easeOut}) // 2. Curtain Scene var scene = new ScrollScene({triggerElement: "#screen2 .imacInner"}) .addTo(controller) .setTween(tlCurtain);
Firstly we create the ScrollMagic controller, then thetlCurtain
timeline and then we add this timeline to a ScrollMagic scene.
The triggerElement
element for this animation is set to #screen2 .imacInner
, which is an absolute positioned div with fixed dimensions defined in the stylesheet.
.imac { width: 450px; height: 296px; background: url('../img/imac.png') no-repeat top left; margin: 0 auto 200px auto; position: relative; } .imacInner { width: 324px; height: 203px; overflow: hidden; position: relative; left: 63px; top: 17px; }
The parent .imac
also has defined dimensions, background-image
and position: relative
to help us out with the positioning of the .imacInner
screen.
The tlCurtain
consist of these 3 tweens.
$curtain
is a transparent div by default, positioned outside of the iMac screen and then animated in using yPercent: 100
, we then update the color of the SVG fill color to #707070
and animate the $curtain
again offscreen.
Note: all the necessary variables were defined at the top of the main.js
as we’ve discussed last time.
2. Trigger Animation At The Bottom Of The Viewport
Sometimes you want to trigger the animation when the element comes into the view. That’s what you can see with the split animation.
// Timeline var splitAnimation = new TimelineMax({paused: true}); splitAnimation.to(bracketLeft3, 0.3, {xPercent: 50, ease:Power4.easeOut}, "start") .to(bracketRight3, 0.3, {xPercent: -50, ease:Power4.easeOut}, "start") .to(tomato3, 0.3, {scale: 0.5, transformOrigin: "center center", ease:Power4.easeOut}, "start") .to([bracketLeft3, tomatoLeft3, tomatoLeaves3], 0.2, {xPercent: -200, autoAlpha:0, ease:Power4.easeOut}) .to([bracketRight3, tomatoRight3], 0.2, {xPercent: 200, autoAlpha:0, ease:Power4.easeOut}, '-=0.2') .to(letters3, 0.4, {scale: 2, y: "-=50", ease:Cubic.easeOut}, '-=0.2'); // Scene var scene2 = new ScrollScene({triggerElement: "#screen3 .imacInner", triggerHook: 'onEnter', offset: 203}) .addTo(controller) .setTween(splitAnimation);
The splitAnimation
timeline is paused by default and triggered to play when the bottom of the #screen3 .imacInner
hits the bottom of the viewport.
This is achieved by setting offset: 203
, where 203
pixels is the height of the iMac screen.
If we didn’t include the offset
, the animation would start when the top of the screen hits the bottom of the browser viewport.
3. Trigger Animation At The Top Of The Viewport
The scale down and rotation animation is triggered at the top of the viewport.
// Timeline var fallAnimation = new TimelineMax({paused: true}); fallAnimation.set(screen4, {background: "none"}) .to(screen4svg, 0.3, {scale: 0.7, transformOrigin: "bottom center", y: "+=40px"}, "start") .to(screen4ihtLogo, 0.3, {rotation: 720, transformOrigin: "bottom center"}, "+=0.5"); // Scene var scene3 = new ScrollScene({triggerElement: "#screen4 .imacInner", triggerHook: 'onLeave'}) .addTo(controller) .setTween(fallAnimation);
Again this timeline is paused by default and is played when the top of #screen4 .imacInner
hits the top of the viewport.
Use triggerHook: 'onLeave’
to trigger your animations at the top.
4. Animation Controlled By Scrolling
My final animation example is controlled by the scrollbar.
There are quite a lot of tweens, but hey that’s what makes it look cool (hopefully)!
// Timeline var scrollAnimation = new TimelineMax(); scrollAnimation.set(splitDiv, {autoAlpha: 1}) .to(splitDiv, 0.3, {height: "100px"}) .set([tomatoRight5, letters5], {autoAlpha: 0}) .to(tomato5, 0.6, {rotation: "45", transformOrigin: "bottom left"}, "rotate") .to(splitDiv, 0.3, {y: "70",rotation: "0", transformOrigin: "top center"}, "rotate") .to(bracketRight5, 0.1, {xPercent: 200, autoAlpha:0, ease:Power4.easeOut}, "rotate") .to(bracketLeft5, 0.1, {xPercent: -200, autoAlpha:0, ease:Power4.easeOut}, "rotate") .set(bracketRight5, {xPercent: -200, yPercent: 150, rotation: "90", transformOrigin: "bottom center", autoAlpha: 1}) //bring bracket to the bottom .set(letters5, {y: '-160px', scale: 2, autoAlpha: 0}) //bring text to the top .set(splitDiv, {autoAlpha: 0}) //hide mask .to(bracketRight5, 0.3, {yPercent: 50, autoAlpha: 1, ease:Power4.easeOut}, "catch") .to(tomato5, 0.3, {y: "+=2", rotation: "-=45", scale: 0.5, transformOrigin: "bottom left", ease:Bounce.easeOut}, "catch") .to(tomato5, 0.6, {x: "+=40",y: "+=40", ease:Power4.easeIn}) .to(letters5, 0.3, {y: '-60px', autoAlpha: 1, ease:Power4.easeOut}, "+=0.3"); // bring in text; // Scene var scene4 = new ScrollScene({triggerElement: ".more-link", triggerHook: 'onEnter', triggerOffset: 400, duration: 300}) .addTo(controller) .setTween(scrollAnimation);
The important part is the duration: 300
in the ScrollScene
, which defines the length of the scrolling distance when the animation will play.
A smaller number would mean that the animation would play quicker and higher number would extend the animation playback.
Conclusion
I hope that this article will help you to get started with GreenSock and ScrollMagic, it’s by far the most powerful combination for scrolling animations out there.
Remember, keeping it simple will make your scrolling animations effective.
And if you have any questions regarding any of these plugins, please leave a comment below.
Until next time, happy coding.
Download Free Toolkit
All you need to know to get started with GreenSock and ScrollMagic, in one single package. Straight into your inbox.
Hey, Petr, cool effect, would be nice if the article linked to the products you’re using somewhere.
Cheers,
Atg
Thanks Aaron, I will update the post and link to both ScrollMagic and GreenSock.
Thank you sir. It’s very helping…
Thanks Thisara
What if the content in your scene is taller than the viewport and you have other scenes after it? Seems like Scroll Magic doesn’t like this.
Hey Al, ScrollMagic can work things out for you, but you would need to adjust the CSS and JS.
Not every “visual” scene needs to be a ScrollMagic scene, you can mix it up to achieve the effect you’re after.
Petr,
Do you know if ScrollMagic can do this: http://pitchinteractive.com/nie-rmo-1429290178319
The scroll action is not continuous. I don’t think ScrollMagic is made for this kind of thing, but what do you think?
You’re right Al, ScrollMagic is not build for this and I am not a big fan of this approach either, however a while ago I wrote this One Page Scroll with animations tutorial.
Really consider whether you need to disable the native scrolling behavior before implementing it in your own project.
‘triggerOffset’ doesn’t seem to be recognised and looks like it should be ‘offset’.
‘offset’ used in the doc examples
http://janpaepke.github.io/ScrollMagic/examples/advanced/advanced_tweening.html
You’re right Greg, this has been changed in the ScrollMagic 2.0 update. I am using an older version in this demo.
Thanks for pointing this out.
Are you working on a ScrollMagic project or just having fun with scrolling animations?
Your sample code contains a small error I think.
You quote “The triggerElement element for this animation is set to #screen2 .imacInner, which is an absolute positioned div with fixed dimensions defined in the stylesheet.”
However in the CSS you have .imacInner set as position: relative
Hi Petr,
I bought some time ago the Skrollr tutorials from you, and now I am digging deeper into Skrollmagic, it really is magical 🙂
Had one question I’d hope you could help me with:
I am trying to achieve blur effect on a div, starting at the top when div reaches viewport and finishing at the end (height of the div), no problem there by setting up the code, only when the animation starts it automatically jumps from 0 blur to 10px(example) of blur.
Any idea on this matter?
{‘-webkit-filter’: ‘blur(10px)’}
(other transitions work, such as opacity and so).
Thanks a lot for the tutorials.
Hi Nick, great to hear that you are enjoying the tutorials. Hard to say what’s going on, could you create a simple CodePen demo?
Hi Petr,
Thanks for the quick feedback, I set up the following fiddle:
http://jsfiddle.net/0waum873/1/
Hope this shows a little what I am trying to achieve.
Thanks again for the tuts and your help.
Much appreciated 🙂
Hey Nick, I haven’t played with filters much, but this seems to work for me:
Filter blur with ScrollMagic on CodePen
All you have to do is to pass the filter to the DOM element in a function.
And here’s the related CodePen demo.
Also note that filters are not supported in IE.
Hope that helps.
Hey Petr,
Worked fantastic, as I answered you, thought it would have auto added that to the comments. Anyway so thanks again.
And here I am again, if you got time or could help me with something small (or maybe it’s not that small);
I’m using the section wipes with image backgrounds, I have them set to ‘cover’, but some sections have a vertical overflow, which doesn’t cause any issue, but when that specific section becomes fixed it makes the background image jump, and I can’t figure out the css to avoid this jump,
I did use background size: 100% instead of cover and positioned it vertically against the top, but the problem with this is that if the image is little smaller in height it either repeats itself or when switched off (no-repeat) it leaves a blank space.
On another note, I really enjoy this ScrollMagic a lot, but it seems that the really amazing thing behind the wow effect is Greensock, are you planning on any gsap specific tutorials.
Would be really interested in this.
Sorry for the long read and thanks again.
Enjoy your weekend!
Nick
Hi Petr,
thanks for this awesome article!
It was really helpful to do the tutorial and your explanation was very good, as always 🙂
I found one little mistake in the last animation, where you rotate the tomato.
You wrote this line of code:
But the rotation should be rotation: ‘+=45’ to animate the tomato like in the demo.
Also ScrollMagic is not working anymore if I pause the tween. So with the new version of ScrollMagic I think you don’t have to pause the Timeline initially. Instead just initialize it like this:
Thanks Petr for this great tutorial!
Best regards,
Norman
Thanks for the correction Norman!
Hi Petr,
you’re welcome!
Glad to help you! 🙂
Hi Petr,
Thanks for a great article! Just a small question, is it possible to just “fire” the animation once, or is it always active?
//Fredrik
Hi Frederik, you can set the scene reverse to false to only play the animation once.
Hope that helps and let me know if you have any other ScrollMagic questions.
I’m going to openly admit that much of this is over my head. But what’s life without challenge right?
I added a little GS tweenMax to a few elements for fun and it went pretty smoothly.
Then, I wanted to extend my knowledge to see if I could attach a scroll trigger event that would initialize a tween and stumbled across this article.
I’m trying to add the information in this tutorial to a Bootstrap setup but not getting the results I was hoping for.
I’m not looking for anyone to do the work for me necessarily, but any clues to my missteps would be greatly appreciated.
I’ve got a test page going here that I’ll leave up for a few days.
Many thanks in advance for the feedback and very much appreciate the tutorial.
http://www.shawnkelshaw.com/test.html
Hi Shawn, thanks for the comment and for being honest about the challenge. With a little practice things become easier.
Your test page has a JS error:
Uncaught ReferenceError: $curtain is not defined
. $curtain is a variable that I’ve setup for my demo, you might need to include in your code or remove that tween from the timeline.Can you be more specific about what is over your head? Is that ScrollMagic API or GSAP? Or the mix?
Happy to answer your questions.
Thanks Petr. I really appreciate the reply. I took a look at the $curtain issue you cited and noticed I did indeed have some missing information. Sometimes a good night’s sleep can help. I was also missing some div ids and some styles. I’m taking the “reverse engineering” approach to all this and therefore I’m literally plagiarizing your code from the demo page; I hope that’s ok.
In any event, I think I’ve got something going now. The first animation is now working on pageload as expected as well as the $curtain effect on scene 2. If you have a moment, take a look (http://www.shawnkelshaw.com/test.html). I think I’ll try to start tweaking some of this now… Again, many thanks for the tutorial, the reply and the encouragement.
P.s. I did find some other tutorials on Skollr.js and I’m thinking that approach is more my speed/knowledge. I may give some of that a try here soon.
Hi Shawn, the reverse engineering is absolutely fine, that’s how I like to learn too. Skrollr might be a better option if you just starting out.
Been playing around with magic for a little and its great, but how can you start at first scroll?
I have an elements that is within the viewport when page loading, they will fly up or down when scrolled. The location changes based on user settings, so the elements need to start in the default location. The ‘onEnter’ doesn’t work because when page load the elements have already left their starting position… The only thing I can think of is to make an invisible trigger and place it halfway down the page browser height, but seems a little cumbersome to do it this way.
Is there another way to go about this or a setting im missing?
Hi Jason, have you tried to place invisible trigger to the top of the screen or use the body as the trigger element? Then you could use the
triggerHook: 'onLeave'
to trigger your animations straight on the first scroll.Hope that helps.
Thanks, I didnt think of that way. I ended up having something a little similar, having an invisible div at 50% top then offset it by 2 pixels… Seems both ways would do the job.
Just was wondering if I was missing a command, I was coming from skrollr and it has a data-start command that does this. But after using both I definitely like the power of scroll magic better!
Nice one Jason. There is always more ways how to do the same thing. Thanks for sharing your approach, I am sure it will help others.
I love this, I haven’t figured out how to work get it to work with the latest version of the scrollMagic, yet, but that’s a minor detail.
I do have a question though: I have a page setup that has “blocks” on it, as each block enters, it plays the animation, great. However, the number of blocks that a page may have is a variable that can change and they all use the same “animation”, is there any way to detect if a DOM structure is in view with a particular class instead of targeting the element by an identifier?
Hi Sebastien, thanks for checking it out. Yes, you can create an array of triggers (blocks) based on a class and then create a scene for all of them inside of each loop, but they still need a unique ID, otherwise the first would trigger animations on all the elements with the same class.
I will be covering this and more advanced ScrollMagic animations in the upcoming ScrollMagic Workshop.
Thanks for the reply. I’m not too great with JS, but I figured out if I just put it in a loop using each function, and target “this” instead, it actually will treat each one as a separate element. I don’t know if this is ideal, but it’s smooth and works across all browsers modern browsers.
See code below:
Thanks for sharing your code Sebastien, great to see you figured it out. Cheers
hi Sir
can you give a demo on svg path fill on scrolling,
https://serioverify.com/
like this site
Thanks for the post Petr, I’m using a Pinned container to achieve the horizontal slides effects.
http://scrollmagic.io/examples/advanced/section_slides_manual.html
But seems like using the trigger for animation within each section won’t work anymore, since there’s virtually no vertical movement. Do you have any workaround on this. Thanks a lot
Many thanks in advance for the response and very much appreciate the tutorial. I learned allot to use with my site http://www.martelelectronics.com/