Pau Ferrer Posted February 25 Posted February 25 (edited) Hi there!! 👋🏻 I am using GSAP for the first time and I am loving it!! But I would do with some help on a slider like animation I am creating for a client. This is done in Webflow using Saddle Framework. I will share Read Only link at the bottom of the message, but first some context. The client wants a slider with 2 sets of cards that animates on scroll. We use a switch to go from one slider to the other and here is where I am having a problem... When I click on the switch a new timeline gets set creating a timeline hell situation that scales the more you switch between the 2 sliders... I've tried to kill the tweens with ".killTweenOf()", to use the timeline object and kill it to reset it, and nothing seams to work... Here is my JavaScript: // wait for DOM and scripts to load window.addEventListener('load', ()=> { // GSAP Services Slider Switch Animation const section = document.querySelector('[bs-servicesSlider-element="section"]') const switchButton = section.querySelector('[bs-switchButton-element="switch"]') const toggle = switchButton.querySelector('[bs-switchButton-element="toggle"]') const leftText = switchButton.querySelector('[bs-switchButton-element="leftText"]') const rightText = switchButton.querySelector('[bs-switchButton-element="rightText"]') const retailerTrack = document.querySelector('[bs-servicesSlider-element="retailerTrack"]') const brandTrack = document.querySelector('[bs-servicesSlider-element="brandTrack"]') const items = [...document.querySelector('[bs-servicesSlider-element="list"]').children] const retailerItems = items.filter(item => item.children[1].innerHTML === 'Retailer') retailerItems[retailerItems.length - 1].style.borderRight = "none" retailerTrack.append(...retailerItems) const brandItems = items.filter(item => item.children[1].innerHTML === 'Brand') brandItems[brandItems.length - 1].style.borderRight = "none" brandTrack.append(...brandItems) const retailerProgressBar = section.querySelector('[bs-servicesSlider-element="retailerProgressBar"]') const brandProgressBar = section.querySelector('[bs-servicesSlider-element="brandProgressBar"]') let click = 0 // GSAP Service Slider Scroll Animation const commons = { duration: .4, ease: "circ.inOut" } const scrollTriggerCommons = { start: 'top 25%', end: '200% 25%', scrub: true, markers: true, toggleActions: 'play pause reverse pause' } const retailerStrollTrigger = { trigger: retailerTrack, ...scrollTriggerCommons } const brandScrollTrigger = { trigger: brandTrack, ...scrollTriggerCommons } const setSliderAnimation = () => { const track = click === 0 ? retailerTrack : brandTrack const progressBar = click === 0 ? retailerProgressBar : brandProgressBar const scrollTrigger = click === 0 ? retailerStrollTrigger : brandScrollTrigger const trackPosition = window.innerWidth - track.offsetWidth gsap.to(track, { x: trackPosition, ease: commons.ease, scrollTrigger: scrollTrigger }) trackPosition === 0 ? progressBar.parentElement.classList.add('u-hide') : progressBar.parentElement.classList.remove('u-hide') gsap.to(progressBar, { width: progressBar.parentElement.offsetWidth, ease: commons.ease, scrollTrigger: scrollTrigger }) } // GSAP Toggle Animation const toggleAnimation = () => { gsap.to(toggle, { xPercent: click === 0 ? 0 : 100, }) setTimeout(() => { if(click === 0) { rightText.classList.add('u-hide') leftText.classList.remove('u-hide') } if(click === 1) { leftText.classList.add('u-hide') rightText.classList.remove('u-hide') } }, 200) } // GSAP Theme Animation const theme = { lightGrey: '#f0f0f0', darkGrey: '#232323', yellow: '#e8f83d' } const themeAnimation = () => { gsap.to(section, { backgroundColor: click === 0 ? theme.yellow : theme.darkGrey, color: click === 0 ? theme.darkGrey : theme.lightGrey, ...commons }) gsap.to(section.querySelector('.subheading_line'), { backgroundColor: click === 0 ? theme.darkGrey : theme.lightGrey, ...commons }) gsap.to(switchButton, { backgroundColor: click === 0 ? theme.darkGrey : theme.yellow, color: click === 0 ? theme.lightGrey : theme.darkGrey, ...commons }) gsap.to(toggle, { backgroundColor: click === 0 ? theme.lightGrey : theme.darkGrey, color: click === 0 ? theme.darkGrey : theme.lightGrey, ...commons }) gsap.to([...retailerTrack.children, ...brandTrack.children], { borderColor: click === 0 ? theme.darkGrey : theme.lightGrey, ...commons }) } // GSAP Switch Click Animations const changeTrack = () => { gsap.to(click === 0 ? brandTrack : retailerTrack, { opacity: 0, ...commons }) if(click === 0) { brandTrack.classList.add('u-hide') retailerTrack.classList.remove('u-hide') retailerProgressBar.classList.remove('u-hide') brandProgressBar.classList.add('u-hide') } else { retailerTrack.classList.add('u-hide') brandTrack.classList.remove('u-hide') retailerProgressBar.classList.add('u-hide') brandProgressBar.classList.remove('u-hide') } gsap.to(click === 0 ? retailerTrack : brandTrack, { opacity: 1, ...commons }) } switchButton.onclick = (event) => { event.preventDefault() click = click === 0 ? 1 : 0 toggleAnimation() themeAnimation() changeTrack() gsap.to(window, { ...commons, scrollTo: { y: "#service-slider_outer", offsetY: 80, autoKill: true }, }) gsap.killTweensOf([retailerTrack, brandTrack], "x") setSliderAnimation() } // Resizing function const displayedCards = { desktop: 3, tablet: 2, mobile: 1 } const resizeTrack = (screenWidth, track) => { let cardsDisplayed = displayedCards.desktop if(screenWidth <= 991) { cardsDisplayed = displayedCards.tablet } if(screenWidth <= 568) { cardsDisplayed = displayedCards.mobile } track.style.width = `${(screenWidth / cardsDisplayed) * track.children.length}px` } // Init Animation resizeTrack(window.innerWidth, retailerTrack) resizeTrack(window.innerWidth, brandTrack) changeTrack() themeAnimation() setSliderAnimation() window.onresize = () => { resizeTrack(window.innerWidth, retailerTrack) resizeTrack(window.innerWidth, brandTrack) themeAnimation() changeTrack() setSliderAnimation() } }) You can find the elements in the Webflow project under "services-slider_outer", and the first section inside the inner wrapper has the JS object with the current code. Please, I need help as this is a key element of the project and I cannot create this animation with Webflow's animations since I need to dynamically change the width of the scroll animation. Thanks in advance!!! Link: https://preview.webflow.com/preview/buzket-space-v2?utm_medium=preview_link&utm_source=designer&utm_content=buzket-space-v2&preview=ff7a7c3ed6298bc1e243bd83225520d8&workflow=preview Edited February 25 by Pau Ferrer Forgot the link to the project...
GSAP Helper Posted February 25 Posted February 25 Without a minimal demo, it's very difficult to troubleshoot; the issue could be caused by CSS, markup, a third party library, a 3rd party script, etc. Would you please provide a very simple CodePen or Stackblitz that illustrates the issue? Please don't include your whole project. Just some colored <div> elements and the GSAP code is best. See if you can recreate the issue with as few dependencies as possible. Start minimal and then incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, at least we have a reduced test case which greatly increases your chances of getting a relevant answer. See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen. that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo: Using a framework/library like React, Vue, Next, etc.? CodePen isn't always ideal for these tools, so here are some Stackblitz starter templates that you can fork and import the gsap-trial NPM package for using any of the bonus plugins: React (please read this article!) Next Svelte Sveltekit Vue Nuxt Please share the StackBlitz link directly to the file in question (where you've put the GSAP code) so we don't need to hunt through all the files. Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. ✅
Rodrigo Posted February 25 Posted February 25 Hi, Here is a simple demo of a content slider: See the Pen VYZwvza by GreenSock (@GreenSock) on CodePen. Hopefully this helps Happy Tweening!
Pau Ferrer Posted February 25 Author Posted February 25 Thanks for that!! I am currently working on a CodePen example to illustrate the issue as recommended. Will post it here as soon as I have it ready.
Pau Ferrer Posted February 25 Author Posted February 25 (edited) And here is the CodePen link See the Pen dPypZOj by Pau-Ferrer-the-animator (@Pau-Ferrer-the-animator) on CodePen. Edited February 25 by Pau Ferrer Updated the link
mvaneijgen Posted February 26 Posted February 26 Why don't you just create both sliders and ScrollTriggers at the same time and then just on click of the which set the one to opacity: 0 and the other to opacity: 1 don't toggle the whole ScrollTrigger logic. This means both animations will be playing no matter what, but nobody would see this because they are not visible. I would also not have separate ScrollTriggers for the track and the progress bar, just have a timeline with a ScrollTrigger to control that whole setup and thus duplicate the progress bar for the second "slider", I did a quick proof of concept and you can for sure use a loop to create the to timeline with ScrollTrigger logic. Hope it helps and happy tweening! See the Pen QwWKPQO?editors=0010 by mvaneijgen (@mvaneijgen) on CodePen.
Pau Ferrer Posted February 26 Author Posted February 26 Thanks @mvaneijgen!! That made lots of sense and I managed to fix it thanks to your advise!! Here is the final solution as I needed the switch toggle to animate and also to not refresh the page on click event... So I targeted the tracks parents to hide/show and the slider mask as the scroll trigger so the start and end markers match!! Thanks a lot!! And thanks to GSAP for this amazing tool!! I am enjoying it very much!! And not coming back!! Link here: See the Pen dPypZOj by Pau-Ferrer-the-animator (@Pau-Ferrer-the-animator) on CodePen.
Pau Ferrer Posted February 26 Author Posted February 26 And final adjustments for perfect functionality (minus responsiveness... 😅) See the Pen dPypZOj by Pau-Ferrer-the-animator (@Pau-Ferrer-the-animator) on CodePen.
mvaneijgen Posted February 26 Posted February 26 Great job solving your issue! For responsive ness also check https://gsap.com/docs/v3/GSAP/gsap.matchMedia()/ and use https://gsap.com/docs/v3/GSAP/Tween/#function-based-values to have GSAP calculate new values on ScrollTrigger.refresh() which is automatically does on page resize. Good luck and happy tweening!
Pau Ferrer Posted March 3 Author Posted March 3 Hey @mvaneijgen... sorry to bring this issue back, but the start and end points are getting refreshed in mobile when I scroll up fast and the address bar shrinks and this is making my animation to not work again... I show a potential solution in another post using this code: ScrollTrigger.config({ autoRefreshEvents: "visibilitychange,DOMContentLoaded,load" // notice "resize" isn't in the list }); But it is not working for me... I am using Chrome in a iOS phone... I also tried this without success... // only fire callbacks when the active state toggles ScrollTrigger.config({ ignoreMobileResize: true, }); I cannot represent the issue in a CodePen project since it is particular of mobile phones... sorry I can provide the staging URL I am using to test development tho. https://buzket-space-v2.webflow.io/ Thanks in advance!!!
mvaneijgen Posted March 3 Posted March 3 You can also look at https://gsap.com/docs/v3/Plugins/ScrollTrigger/static.normalizeScroll()/ Codepen is totally fine for debugging on mobile btw, you can open the /debug view of your pen on mobile to get the full native web interface, so if you want to help us debug please post a Codepen and we'll be happy to help you debug! 1
Pau Ferrer Posted March 3 Author Posted March 3 If I could I would give you a hug @mvaneijgen!!! That worked beautifully!!! And I didn't know you could use CodePen for mobile debuging!! Thanks for that tip!!
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