VIPStephan Posted December 21, 2020 Posted December 21, 2020 Hi, I’m new here and I’m trying to have a fixed header fade out upon scrolling down, with a button to have it fade in and out manually (if scrolled down). I’ve got the fade-on-scroll part working but I’m struggling with the fade toggle. I thought I would create some tweens and two independent timelines to which I add the tweens (with different timing in each timeline), and then I associate one timeline with ScrollTrigger and the other one will be executed on click of the button but somehow this doesn’t work. Note, I’m using this in combination with jQuery This is the code I have so far: var anim_header = gsap.timeline({ scrollTrigger: { trigger: $('body'), scrub: true, //markers: true, start:'top top', end: '+='+$('body > header').outerHeight()*1.75+'px' } }), toggle_header = gsap.timeline().pause(), fadeHeader = gsap.to($('body > header'), { opacity: 0 }); anim_header.add(fadeHeader); toggle_header.add(fadeHeader); toggleButton.click(function() { if(!$('html').hasClass('header_active')) { toggle_header.reverse().then(function() { $('html').addClass('header_active'); }); } else { toggle_header.play(); $('html').removeClass('nav_active'); } }); I thought I could just add the same tween to different timelines and they would work independently but apparently this isn’t working; it seems like one timeline overrides the other one.
ZachSaucier Posted December 22, 2020 Posted December 22, 2020 Hey Stephan, welcome to the GreenSock forums. 18 hours ago, VIPStephan said: I thought I could just add the same tween to different timelines and they would work independently This is not true. You could create two equivalent tweens and to do something similar but you can't share one tween in multiple timelines and expect them to be independent - the variable reference is the same. It looks to me like you're overcomplicating things but it's pretty hard for us to know exactly what sort of setup you need without a minimal demo to see and edit ourselves. Can you please create one?
VIPStephan Posted December 22, 2020 Author Posted December 22, 2020 Thanks Zach. I’m more a JSFiddle guy, so I’ve created a minimal example here: https://jsfiddle.net/q54n1ofx/ That’s what my original first implementation was. I know it’s still rough but my thinking was that it would fade out on scroll and if the “button” is clicked it will fade in or out depending on an “active” class added to the container by just reversing or playing the animation again. This kind of works but once we’re in the range of the scroll trigger again it behaves in a weird way.
ZachSaucier Posted December 22, 2020 Posted December 22, 2020 Thanks for the demo. The issue is logical: You have a ScrollTrigger that's trying to set the value of the opacity every time it updates. But you also want the clicking to control the opacity. So when the scroll position is within the ScrollTrigger's top and end values and someone clicks the button, you have conflict. You have to decide: what do you want to happen when they are in conflict? Should the ScrollTrigger be disabled? Should the button clicking be ignored? Should the button's effect be prioritized but on the next update of the ScrollTrigger it gets control back? There are many ways you could get it working depending on what you want. What do you want? 1
VIPStephan Posted December 22, 2020 Author Posted December 22, 2020 Well, this was just the first implementation. My first step was to get it to fade out when scrolling down, and when clicking the button while being outside of the ScrollTrigger area, it’s supposed to fade in or out. Then, when scrolling up again, it should fade in if it’s invisible or it should just stay visible, whatever it was when the button had been clicked last time. Eventually, this will be a header with a menu which will prevent scrolling the body altogether when active, so the only thing the script has to worry about is to fade in/out on click, and to fade in when scrolling up to the top. At the top it shouldn’t fade at all since it’s visible already, and if it’s half way opaque it should fade to full opacity upon activating or to the state of opacity determined by the scroll position upon deactivating the button. I hope my explanations made sense.
ZachSaucier Posted December 22, 2020 Posted December 22, 2020 I think it'd make more sense if you did something like this: https://jsfiddle.net/vzk28tnr/ 1
VIPStephan Posted December 22, 2020 Author Posted December 22, 2020 Hmm, well, for something like this I wouldn’t even need GSAP, I could do this with a simple class toggle and CSS transitions. I specifically like the fade connected to the scroll position. OK, so, I’m thinking of working around this with a hybrid approach: have it fade out while scrolling, and onLeave reset it (to remove all inline styles) and set a class that takes over the hiding. Then, on click I can work with the class toggle and CSS transitions, and onEnterBack, set the ScrollTrigger animation again. Does that sound feasible? I’ve had some success with disable() onLeave but it won’t enable() again onEnterBack.
ZachSaucier Posted December 23, 2020 Posted December 23, 2020 1 hour ago, VIPStephan said: Does that sound feasible? Sure. As I said this is mostly a logical issue. Any solution that fixes the logic works 1 hour ago, VIPStephan said: I’ve had some success with disable() onLeave but it won’t enable() again onEnterBack. There's no way that onEnterBack could work because you disabled it...
VIPStephan Posted December 23, 2020 Author Posted December 23, 2020 15 hours ago, ZachSaucier said: There's no way that onEnterBack could work because you disabled it... Ah, right. Is there a way to reset everything to “unspecified” (removing all inline styles applied by ScrollTrigger) while still having ScrollTrigger enabled and ready to react onEnterBack? Hm, thinking about this a little more, it sounds like it’s overcomplicating things, too. I guess the best is to calculate the point of re-entry manually and then just enable() the ScrollTrigger again.
ZachSaucier Posted December 23, 2020 Posted December 23, 2020 1 hour ago, VIPStephan said: Is there a way to reset everything to “unspecified” (removing all inline styles applied by ScrollTrigger) Sure, but the best way of how to do so likely depends on exactly what you're trying to do. Please create a minimal demo of what you're trying to do and where you're getting stuck if you'd like additional help.
VIPStephan Posted December 29, 2020 Author Posted December 29, 2020 OK, after a bit of fiddling around I changed the approach a bit. So, the overall goal is to have the header fade out on scroll, and past a certain point all inline styles should be removed and instead be controlled by a CSS class in the stylesheet for better separation of concerns. Eventually, a click on the toggle button should just change the class name and CSS transitions will do the rest. Now, I managed to disable and enable the ScrollTrigger instance by creating another ScrollTrigger instance that does just that, as shown in this minimal demo: https://jsfiddle.net/8kpt53wq/2/ However, I thought that ScrollTrigger.disable() will revert everything to unspecified but it will revert everything by setting new inline styles to the initial computed values which defeats the purpose because my CSS class will be overridden by these inline styles. How can I remove all inline styles onLeave and re-add them onEnterBack?
ZachSaucier Posted December 29, 2020 Posted December 29, 2020 Use clearProps: header_fade.disable(false); gsap.set(pageHeader, { clearProps: true });
VIPStephan Posted January 11, 2021 Author Posted January 11, 2021 I’m sorry to keep on bothering you with questions but I’m trying things as we go here since it’s the first time I’m implementing something like this. Although it has been helpful, I felt like I was getting nowhere with the previous approach, so I changed it yet again. Basically, I created two timelines, one for the animation while scrolling and one for the animation on click of the toggle button; here’s the demo: https://jsfiddle.net/dfp2z0s7/1/ It works alright on its own, i. e. scrolling down/up, the header fades out/in, and while scrolled down, clicking the button fades in/out the header. The tricky part is if the document is just scrolled so much that the header is just half transparent: it should fade in completely from where it currently is and should also fade out to its current half-transparent state if the button is clicked again. At the moment it looks like the first time it works but for consecutive clicks, if it’s scrolled a bit it will start from the CSS state before the scroll. Any idea?
ZachSaucier Posted January 11, 2021 Posted January 11, 2021 Hey Stephan. It's quite okay to keep asking questions, but I'm afraid my answer is pretty much the same: it's a logical issue The timeline is the same after the first click which is not what you want. You'll have to create a new animation each time that the toggle is clicked if you want to retain the scrubbing. However if the user clicks to make the nav fully opaque and then scrolls again you again have a logical issue of which one should be in control. So you'd need to either disable the ScrollTrigger if the user has clicked the nav is "open" or you could switch the state of the clicking if the user scrolls while the nav is "open". 1
VIPStephan Posted January 11, 2021 Author Posted January 11, 2021 OK, eventually this whole thing will open a navigation and scrolling will be disabled in the “active” state, so scrubbing isn’t an issue there. It’s really only the fade-in from wherever it currently is (i. e. at the very top there will be no animation, a little bit down there will be an animation from, say, 50% opacity to 100% and back to 50% upon deactivating, and further down there will be an animation from 0 to 100% opacity and back). So, I think it’s not as difficult as it seems. Here is an adjusted demo with scrolling disabled in the active state: https://jsfiddle.net/dfp2z0s7/2/ Scroll down until the header is fully transparent, click the button at the top right two times and it will fade in and out nicely. Then scroll back up to the top and click the button again. Why does it animate from zero opacity to one, not from where it currently is? In the timeline only a “to” method is specified, so I would expect it to calculate the current value everytime the animation is called, or where am I thinking wrongly?
Solution ZachSaucier Posted January 11, 2021 Solution Posted January 11, 2021 1 hour ago, VIPStephan said: Why does it animate from zero opacity to one, not from where it currently is? In the timeline only a “to” method is specified, so I would expect it to calculate the current value everytime the animation is called, or where am I thinking wrongly? I answered this in my last post: 5 hours ago, ZachSaucier said: The timeline is the same after the first click which is not what you want. You'll have to create a new animation each time that the toggle is clicked if you want to retain the scrubbing. Putting that logic into a demo: https://jsfiddle.net/4v5ar7m2/
VIPStephan Posted January 12, 2021 Author Posted January 12, 2021 Thanks, man, that does the trick. :) I just assumed that the starting state of properties in tweens will always be recalculated (because it does it the first time anyway).
ZachSaucier Posted January 12, 2021 Posted January 12, 2021 49 minutes ago, VIPStephan said: I just assumed that the starting state of properties in tweens will always be recalculated (because it does it the first time anyway). No, that would be very inefficient. Probably more inefficient than you realize
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now