Jump to content
Search Community

Search the Community

Showing results for 'resize' in content posted in GSAP.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • GreenSock Forums
    • GSAP
    • Banner Animation
    • Jobs & Freelance
  • Flash / ActionScript Archive
    • GSAP (Flash)
    • Loading (Flash)
    • TransformManager (Flash)

Product Groups

  • Club GreenSock
  • TransformManager
  • Supercharge

Categories

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Personal Website


Twitter


CodePen


Company Website


Location


Interests

Found 2,294 results

  1. That's my fault, I tried to narrow down my issue as much as possible to simplify it and obviously the context was important! The real issue I'm having is actually related to splittext and resizing in Nuxt, and I'm unable to include splittext in a demo since it's a club plugin and I can't for the life of me figure out how to set up a nuxt environment in codepen. What I would like to do is this: 1. On resize, immediately reset the split to its original state so that the text resizes 'naturally'. 2. Debounce re-creating the timeline 3. Set the timeline's progress to 1 so the whole thing looks like it never happened. Then, when the user goes on their merry way interacting with this element, it animates as it's supposed to, having resized and done all its business. function createTimeline() { split = new SplitText('.text', { type: 'lines' }) timeline = gsap.timeline({ paused: true, defaults: { delay: 0.15 } }) .fromTo(split.lines, { y: '100%', x: 10, autoAlpha: 0, scale: 0.99 }, { duration: 1, y: 0, x: 0, autoAlpha: 1, scale: 1, stagger: 0.07, ease: 'power2.inOut' }) } function recreateTimeline() { createTimeline() timeline.progress(1) } const debounceHandler = debounce(recreateTimeline, 300) function handleResize() { if(timeline){ timeline.revert() split.revert() } debounceHandler() } onMounted(() => { window.addEventListener('resize', handleResize) }) What ACTUALLY happens is probably an issue with Nuxt more than anything (or maybe I'm missing something!), but it's the reason I thought I had to wait for .revert(). When I run handleResize(), the timeline and split are reverted and the debounceHandler is called just fine. The problem is that when recreateTimeline() calls createTimeline(), the split is not properly reverted and SplitText() runs on text that's already been split. Even though it should've been reset to its original state when handleResize() was first called. It's like the reverts never happened, or if they did they got stuck halfway. The timeline doesn't recreate properly and none of the animations run after resize. This does not happen if I debounce the entire handleResize function but I don't want to do that because when the user resizes the window down, they will see the incorrectly positioned text for 300ms or however long I set the debounce to. What I ended up having to do is this horrorshow: Basically I'm having to call the reset behavior multiple times to make sure it's cleaned up even though the reset DOES happen immediately, but for reasons I don't yet understand, not correctly or fully. let timeline let split function createTimeline() { split = new SplitText('.text', { type: 'lines' }) timeline = gsap.timeline({ paused: true, defaults: { delay: 0.15 } }) .fromTo(split.lines, { y: '100%', x: 10, autoAlpha: 0, scale: 0.99 }, { duration: 1, y: 0, x: 0, autoAlpha: 1, scale: 1, stagger: 0.07, ease: 'power2.inOut' }) } function destroyTimeline() { timeline?.revert() split?.revert() split = null timeline = null } function recreateTimeline() { destroyTimeline() nextTick(() => { createTimeline() timeline.progress(1) }) } const debounceTimeline = debounce(recreateTimeline, 300) function handleResize() { timeline?.revert() split?.revert() debounceTimeline() } onMounted(() => { window.addEventListener('resize', handleResize) }) If you're still reading by this point, I salute your immense patience. Basically I thought that MAYBE the issue was that reverts() weren't immediate, and I had to await them before running anything that relied on them being complete.
  2. Hi all, I'm working with SplitText and I need to be able to revert everything, reset timelines, and then recreate and re-run everything on resize. The main issue I'm having is chaining everything nicely. timeline.reverse() returns itself 'for easy chaining' according to the docs. Except you can't chain timeline.reverse().then() (this throws an error) and wrapping it in a promise doesn't work either. What is the best way to make sure everything has been fully reverted when wrapping reverts in external functions? Because if I dump everything into one function, things do get cleaned up correctly, but we obviously don't want to do that.
  3. Thanks for clarifying, I'll definitely be using this syntax in the future! If this isn't too far out of the scope of my initial issue, I managed to reproduce something I'm running into with these tweens. I have two instances of the same component (it's all in the demo) – one on the page and one inside a modal. For their timelines to run independently I need to declare them as Vue refs. Which is fine, except for some reason when the timeline is reset on reside, the timeline for the other instance of the component gets messed up. For example in this demo, scroll down to activate the on-page animation, resize it, scroll again to re-activate it, then toggle the modal. The modal splitText animation doesn't run correctly, probably because the split isn't properly recalculated. I suspect it's a vue-specific issue but if there's any way to negate it I'm all ears! Here's the demo: https://stackblitz.com/edit/nuxt-starter-zdudyt?file=app.vue,components%2FTextComponent.vue
  4. I have an animation which uses pinning. However it doesn't reset the pin positions on browser resize. I have been at it for literally weeks now and have had no luck. Annoyingly it works on my demo but not on my live site https://staging-chfp.shereewalker.com/ Initially it looks fine, but when you actually open it on a mobile, it's completely breaks on screen orientation change. I think it might partly be caused by me hiding and displaying the animated section, but even at heights where this doesn't take effect, the markers are consistently off. I have included the code for the animation that sits above (the expanding image) because I thought this might be the cause, but the demo STILL works. I have had support on here before but nothing seems to work, so really all I am trying to do at this point is kill it entirely, and re-add/calculate on browser resize. But I can't even get this to work. Any help would be greatly appreciated. Note: You won't see the pinning unless you open the codepen link as the height is to small in this thread
  5. Hello I have a bento style gallery and on scroll the rows and columns of the gallery are changing size so the middle element is zoomed in and take full screen size. In the code pen provided you will see that everything works ok until you resize the window. I found out that if the scale option is set to true then the grid and images adapt to the new window size but images are distorted as the parent element is now scaled with a transform and I cannot have that. Is there any way of reseting Flip and ScrollTrigger to calculate everything from scratch but for the new window size? Or any other solution i'm missing at the moment? Thank you very much for your help!
  6. Hi, I'm not 100% sure of what issue you're experiencing, but waiting for 1 tick of GSAP's ticker should be enough. As far as I can tell, after you revert your GSAP instances and create the new ones, it should take 1 tick to render the new ones, so that should be enough. Based on your demo this is how I would proceed: const tweenable = document.getElementById('tweenable') let tween, timer; const createTween = () => { tween = gsap.timeline().fromTo(tweenable, {opacity: 1}, {opacity: 0, duration: 1}); }; const revertTween = () => { tween && tween.revert(); createTween(); }; window.addEventListener("resize", () => { timer && clearTimeout(timer); timer = setTimeout(() => { revertTween(); }, 200); }); createTween(); Here is a fork of your demo: https://codepen.io/GreenSock/pen/oNOVzdg Hopefully this helps. Happy Tweening!
  7. I am struggling to get this effect to work. There is a hero image with parallax that is working. But the logo, which starts full size and fixed to the bottom of the hero container (with a slight overlap of about 75px at the bottom), needs to resize smaller to fit in the sticky header at the top. This should scrub with the scrollbar and be sticky at the top shortly before the hero is fully scrolled past. I've spent days trying to get this to work, and I can't find any examples anywhere that have helped me get to the bottom of the issue. Any help would be greatly appreciated!
  8. Hello GSAP, Currently I'm using the horizontal loop helper function to create horizontal drag, I have a problem: I only want it to work at breakpoints of 768px or less. When I'm at 768px (tablet breakpoint) I start dragging and when I resize the window it's higher than the tablet breakpoint. How can I completely cleanup that function?! I could clearProps and kill the draggable instance but it doesn't seem possible. You can test the demo by resizing the window for better clarity. Thank you Link stackblit: https://stackblitz.com/edit/stackblitz-starters-ebfeuj?file=app%2Fpage.tsx I'm using useGSAP, and Nextjs. Demo.mp4
  9. Hello! I am trying to make a horizontal slider with images that are 100vw and 100vh. The slider works fine until I do a resize. Then the start marker jumps wildly and no longer starts from the image. I want the pin to update when I do a resize, but it behaves somewhat erratically. I made a codepen but it works fine on that! adding a printscreen! Thanks
  10. Hi there, am I correct that the white space only appears during the resize? If so that's just the browser recalculating and adjusting the layout. I wouldn't see that as an issue. The only people that really resize browser windows are developers anyway! From years of bug testing websites and watching user journeys, the average user doesn't resize the browser, and if they do, they certainly don't care what the website looks like during resize. As long as the layout settles and is useable you're a ok.
  11. Hi Forum, i'm having troubles refreshing the scrolltriggers in my angular project. So when the site is loaded, everything works fine, but when i resize the video in the container i not perfectly aligned anymore. I've set up a minimal demo on stackblitz: Stackblitz Demo EDITNOTE: changed from codesandbox to stackblitz due to sharing issues see: app/src/pages/home/home.component.ts as you can see, i tried some solutions I found on here the forums like invalidateOnRefresh and ScrollTrigger.refresh(true), but none of these work. Desired behaviour after resize: Actual behaviour after resize: I appreciate any help/hint/idea Thank you!
  12. Yeah, you could keep track of the state of one set of images and use Flip's fit() method: https://gsap.com/docs/v3/Plugins/Flip/static.fit() Also in order to keep things optimized you can check the state of the images only at startup and then on a window resize using a debounce method for that. Happy Tweening!
  13. Ah, that's because inside the helper function there was a "resize" event handler that was re-initiating things. I just edited the helper function to put it inside a gsap.context() that uses a cleanup function for the "resize" event handler to remove that: https://stackblitz.com/edit/stackblitz-starters-jbsvf4?file=app%2Fhelper.js function horizontalLoop(items, config) { let timeline; items = gsap.utils.toArray(items); config = config || {}; gsap.context(() => { // use a context so that if this is called from within another context or a gsap.matchMedia(), we can perform proper cleanup like the "resize" event handler on the window let onChange = config.onChange, lastIndex = 0, tl = gsap.timeline({repeat: config.repeat, onUpdate: onChange && function() { let i = tl.closestIndex(); if (lastIndex !== i) { lastIndex = i; onChange(items[i], i); } }, paused: config.paused, defaults: {ease: "none"}, onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100)}), length = items.length, startX = items[0].offsetLeft, times = [], widths = [], spaceBefore = [], xPercents = [], curIndex = 0, indexIsDirty = false, center = config.center, pixelsPerSecond = (config.speed || 1) * 100, snap = config.snap === false ? v => v : gsap.utils.snap(config.snap || 1), // some browsers shift by a pixel to accommodate flex layouts, so for example if width is 20% the first element's width might be 242px, and the next 243px, alternating back and forth. So we snap to 5 percentage points to make things look more natural timeOffset = 0, container = center === true ? items[0].parentNode : gsap.utils.toArray(center)[0] || items[0].parentNode, totalWidth, getTotalWidth = () => items[length-1].offsetLeft + xPercents[length-1] / 100 * widths[length-1] - startX + spaceBefore[0] + items[length-1].offsetWidth * gsap.getProperty(items[length-1], "scaleX") + (parseFloat(config.paddingRight) || 0), populateWidths = () => { let b1 = container.getBoundingClientRect(), b2; items.forEach((el, i) => { widths[i] = parseFloat(gsap.getProperty(el, "width", "px")); xPercents[i] = snap(parseFloat(gsap.getProperty(el, "x", "px")) / widths[i] * 100 + gsap.getProperty(el, "xPercent")); b2 = el.getBoundingClientRect(); spaceBefore[i] = b2.left - (i ? b1.right : b1.left); b1 = b2; }); gsap.set(items, { // convert "x" to "xPercent" to make things responsive, and populate the widths/xPercents Arrays to make lookups faster. xPercent: i => xPercents[i] }); totalWidth = getTotalWidth(); }, timeWrap, populateOffsets = () => { timeOffset = center ? tl.duration() * (container.offsetWidth / 2) / totalWidth : 0; center && times.forEach((t, i) => { times[i] = timeWrap(tl.labels["label" + i] + tl.duration() * widths[i] / 2 / totalWidth - timeOffset); }); }, getClosest = (values, value, wrap) => { let i = values.length, closest = 1e10, index = 0, d; while (i--) { d = Math.abs(values[i] - value); if (d > wrap / 2) { d = wrap - d; } if (d < closest) { closest = d; index = i; } } return index; }, populateTimeline = () => { let i, item, curX, distanceToStart, distanceToLoop; tl.clear(); for (i = 0; i < length; i++) { item = items[i]; curX = xPercents[i] / 100 * widths[i]; distanceToStart = item.offsetLeft + curX - startX + spaceBefore[0]; distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, "scaleX"); tl.to(item, {xPercent: snap((curX - distanceToLoop) / widths[i] * 100), duration: distanceToLoop / pixelsPerSecond}, 0) .fromTo(item, {xPercent: snap((curX - distanceToLoop + totalWidth) / widths[i] * 100)}, {xPercent: xPercents[i], duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond, immediateRender: false}, distanceToLoop / pixelsPerSecond) .add("label" + i, distanceToStart / pixelsPerSecond); times[i] = distanceToStart / pixelsPerSecond; } timeWrap = gsap.utils.wrap(0, tl.duration()); }, refresh = (deep) => { let progress = tl.progress(); tl.progress(0, true); populateWidths(); deep && populateTimeline(); populateOffsets(); deep && tl.draggable ? tl.time(times[curIndex], true) : tl.progress(progress, true); }, onResize = () => refresh(true), proxy; gsap.set(items, {x: 0}); populateWidths(); populateTimeline(); populateOffsets(); window.addEventListener("resize", onResize); function toIndex(index, vars) { vars = vars || {}; (Math.abs(index - curIndex) > length / 2) && (index += index > curIndex ? -length : length); // always go in the shortest direction let newIndex = gsap.utils.wrap(0, length, index), time = times[newIndex]; if (time > tl.time() !== index > curIndex && index !== curIndex) { // if we're wrapping the timeline's playhead, make the proper adjustments time += tl.duration() * (index > curIndex ? 1 : -1); } if (time < 0 || time > tl.duration()) { vars.modifiers = {time: timeWrap}; } curIndex = newIndex; vars.overwrite = true; gsap.killTweensOf(proxy); return vars.duration === 0 ? tl.time(timeWrap(time)) : tl.tweenTo(time, vars); } tl.toIndex = (index, vars) => toIndex(index, vars); tl.closestIndex = setCurrent => { let index = getClosest(times, tl.time(), tl.duration()); if (setCurrent) { curIndex = index; indexIsDirty = false; } return index; }; tl.current = () => indexIsDirty ? tl.closestIndex(true) : curIndex; tl.next = vars => toIndex(tl.current()+1, vars); tl.previous = vars => toIndex(tl.current()-1, vars); tl.times = times; tl.progress(1, true).progress(0, true); // pre-render for performance if (config.reversed) { tl.vars.onReverseComplete(); tl.reverse(); } if (config.draggable && typeof(Draggable) === "function") { proxy = document.createElement("div") let wrap = gsap.utils.wrap(0, 1), ratio, startProgress, draggable, dragSnap, lastSnap, initChangeX, wasPlaying, align = () => tl.progress(wrap(startProgress + (draggable.startX - draggable.x) * ratio)), syncIndex = () => tl.closestIndex(true); typeof(InertiaPlugin) === "undefined" && console.warn("InertiaPlugin required for momentum-based scrolling and snapping. https://greensock.com/club"); draggable = Draggable.create(proxy, { trigger: items[0].parentNode, type: "x", onPressInit() { let x = this.x; gsap.killTweensOf(tl); wasPlaying = !tl.paused(); tl.pause(); startProgress = tl.progress(); refresh(); ratio = 1 / totalWidth; initChangeX = (startProgress / -ratio) - x; gsap.set(proxy, {x: startProgress / -ratio}); }, onDrag: align, onThrowUpdate: align, overshootTolerance: 0, inertia: true, snap(value) { //note: if the user presses and releases in the middle of a throw, due to the sudden correction of proxy.x in the onPressInit(), the velocity could be very large, throwing off the snap. So sense that condition and adjust for it. We also need to set overshootTolerance to 0 to prevent the inertia from causing it to shoot past and come back if (Math.abs(startProgress / -ratio - this.x) < 10) { return lastSnap + initChangeX } let time = -(value * ratio) * tl.duration(), wrappedTime = timeWrap(time), snapTime = times[getClosest(times, wrappedTime, tl.duration())], dif = snapTime - wrappedTime; Math.abs(dif) > tl.duration() / 2 && (dif += dif < 0 ? tl.duration() : -tl.duration()); lastSnap = (time + dif) / tl.duration() / -ratio; return lastSnap; }, onRelease() { syncIndex(); draggable.isThrowing && (indexIsDirty = true); }, onThrowComplete: () => { syncIndex(); wasPlaying && tl.play(); } })[0]; tl.draggable = draggable; } tl.closestIndex(true); lastIndex = curIndex; onChange && onChange(items[curIndex], curIndex); timeline = tl; return () => window.removeEventListener("resize", onResize); // cleanup }); return timeline; } Is that better?
  14. Hello! I caved the other day and now I'll be doing a LOT of GSAP 😆 Background: I tried replicating the Fake Scroll (Horizontal) demo and integrating it with SmoothScroller on a Svelte/Sveltekit site. It works on CodePen, and similar it works if I stick the SmoothScroller code inside the Horizontal component. Problem: I rather have the SmoothScroller in layout.svelte, because I'm using it across the *entire* site. If I stick it inside the Horizontal component, other things on the page break. If I have both a global and local component instance, other items on the page jitter (I'm assuming the SmoothScrollers are in conflict over the elements). Most of the other components play nicely going forwards (not in reverse or on resize, but that's another problem 😅). I have attempted to replicate the issue with a minimal demo on StackBlitz. It's not exactly the same, but it is similar, so I'm hoping that perhaps someone shedding either some light on how that should work or best practices will help me solve my initial issue. The issue I'm seeing on StackBlitz is that the full number of sections isn't showing; it is similar on my local site, except that it also disappears VERY quickly and there's a ton of space down the page where the animation should be scrolling. One thing at a time, I guess. Help would be immensely appreciated!
  15. Hi, recently i created a code with scrollTrigger. When I resize the browser to check for section responsive, there will white space that appear at right side of the browser briefly (shown as in the image attached). When I didnt apply scrollTrigger, the white space wont appear and the section resize normally. Is there anyway to solve this problem or reduce the white space effect My english isnt that good, any help will be appreciated! Thank you!
  16. Hi, I have a problem with the horizontal scroll when I resize the layout, the width of the panel doesn't adjust to 100%, it stays cut. How can I do? Thanks
  17. The following seems to work well but on resize it does throw things off. I've implemented some resize checks but maybe that's not enough and needs to update the trigger start/end? const landing = ref(null) const logo = ref(null) onMounted(() => { let logoToScale = (window.innerWidth / logo.value.$el.getBBox().width) * 5 const landingResize = () => { logoToScale = (window.innerWidth / logo.value.$el.getBBox().width) * 5 } ScrollTrigger.addEventListener('refreshInit', landingResize) const timelineHeader = gsap.timeline({ scrollTrigger: { id: "ZOOM", trigger: landing.value, scrub: true, start: "top top", end: "+=100% 0", pin: true, markers: true, invalidateOnRefresh: true, } }) timelineHeader .to(logo.value.$el, { scale: logoToScale }) })
  18. Function based values mean that when the ScrollTrigger instance is refreshed that end value will be whatever number/string that function returns. If oyu're doing some sort of calculation whose result might change that calculation will be run again. In the particular snippet you added the end point is based on the height of an element, if a screen resize changes the height of that element then the end point will be recalculated as well. Hopefully this clear things up. Finally it seems that you have created two different threads for the same issue, please let's keep the discussion in just one thread. That will make easier to follow and focus our efforts, thanks! Happy Tweening!
  19. I am going slightly mad. I have spent nearly a week trying to get this to work and I can't understand what's going on. I have been trying to some basic pinning with a clip mask and I just can't get it to behave responsibly. Annoyingly on that codepen URL it's actually okay, but on my website, it's not, which I realise makes things difficult. I have done another codepen with ALL my GSAP code (rather than it reduced to the animation in question which is linked above) and that one glitches more so there must be some offending code elsewhere, but I can't work out what, as it all seems fine to me. https://codepen.io/shereewalker/pen/gOyxppY I am removing each piece of extra JS to see if I can work it out, but so far nothing is working. I am basically just trying to refresh the calculations on window resize for that animation - and actually for all of them Any help would be amazing as I am at my wits end! Thanks!
  20. Hi there, I just can't get the demo to replicate it sorry. I have done this - but it's not perfect. Would you recommed a better way to "call kill() on that animation from inside a 'resize' event handler". / Function to invalidate and remake specific animations function invalidateAndRemakeAnimations() { // Kill the first animation ScrollTrigger.getAll().forEach(trigger => { if (trigger.vars.trigger === ".row._1") { trigger.kill(); } }); // Remake the first animation gsap.to(".row._1", { scrollTrigger: { trigger: ".row._1", start: "top top", scrub: true, pin: true, pinSpacing: false, invalidateOnRefresh: true, markers: true } }); // Kill the second animation ScrollTrigger.getAll().forEach(trigger => { if (trigger.vars.trigger === ".row._3") { trigger.kill(); } }); // Remake the second animation gsap.to("h2.text", { scrollTrigger: { trigger: ".row._3", start: "top top", scrub: true, invalidateOnRefresh: true }, position: "relative" }); } // Initial application of animations invalidateAndRemakeAnimations(); // Listen for orientation change event window.addEventListener("orientationchange", function() { // When orientation changes, invalidate and remake specific animations invalidateAndRemakeAnimations(); });
  21. Again, it's tough to advise without seeing a minimal demo, but I guess the most generic answer I can give would be: "call kill() on that animation from inside a 'resize' event handler". But if you want a more targeted answer for your scenario, please provide a minimal demo that clearly illustrates the problem and we'd be happy to take a peek.
  22. Hi, I have a scrollTrigger animation when a section (.pin-section) hits the middle of the view port. This section is pinned for the same amount of pixels as the section height using end: () => "+=" + document.querySelector('.pin-section').offsetHeight During this pinning I have a star that basically keeps scrolling so the user knows to still scroll. This is done by using the .pin-section element as the trigger again and using the end: () => "+=" + document.querySelector('.pin-section').offsetHeight as the end value once again. As well as the simplified CodePen demo, I've also uploaded the page to a subdomain here: https://ia.inset.agency/production/ The issue I have is if I re-size or refresh the window after the animation has been triggered it breaks the animation. Note: The problem on the simplified CodePen version seems to happen if you resize the window when the animation is in-between the 'start' and 'end' markers, on the actual site link it seems to happen after the 'end' marker, but it's essentially the same thing happening each time. Also on the CodePen example it only happens on resize because when you refresh CodePen it seems to reset all of the positioning. Any help would be really awesome. // pin section in middle of screen var pinMiddle = gsap.timeline({scrollTrigger: { trigger: ".pin-section", start: "50% 50%", toggleActions: "restart pause reverse pause", end: () => "+=" + document.querySelector('.pin-section').offsetHeight, pin: true, markers: true }}) // parallax star var prodStar = gsap.timeline({ scrollTrigger: { trigger: '.pin-section', toggleActions: "restart pause reverse pause", start: '50% 50%', end: () => "+=" + document.querySelector('.pin-section').offsetHeight, scrub: true, markers: true } }) prodStar.to('.parallax-star', {y: -250})
  23. Hey there, the markers are still there I think because the section has display none, but hasn't actually been removed if that makes sense? The heights works fine for me but not on mobile. I sort of have it working with this. // Function to invalidate and remake specific animations function invalidateAndRemakeAnimations() { // Kill the first animation ScrollTrigger.getAll().forEach(trigger => { if (trigger.vars.trigger === ".row._1") { trigger.kill(); } }); // Remake the first animation gsap.to(".row._1", { scrollTrigger: { trigger: ".row._1", start: "top top", scrub: true, pin: true, pinSpacing: false, invalidateOnRefresh: true, markers: true } }); // Kill the second animation ScrollTrigger.getAll().forEach(trigger => { if (trigger.vars.trigger === ".row._3") { trigger.kill(); } }); // Remake the second animation gsap.to("h2.text", { scrollTrigger: { trigger: ".row._3", start: "top top", scrub: true, invalidateOnRefresh: true }, position: "relative" }); } // Initial application of animations invalidateAndRemakeAnimations(); // Listen for orientation change event window.addEventListener("orientationchange", function() { // When orientation changes, invalidate and remake specific animations invalidateAndRemakeAnimations(); }); I have no doubt this is not an elegant solution but I don't really know what else to do - even this doesn't really reset them properly on Safari The media queries will definitely change the document height, but I thought Scrolltrigger automatically calculated on resize. The only other thing I could find was in the common mistakes about 'forgetting to use function based start/end values for things that are dependent on viewport sizing' but I can't work out how to implement it.
  24. Hi there I have looked and I have even removed almost everything off the page except a basic text block. I use src set but the images use object-fit so their containers dont change. Some elements on the page are based on VH but I can't change this. I know that without a broken demo it's near impossible but are you able to just tell me how to correctly kill an animation on resize? Sorry i have confused things by opening another thread. I thought maybe this was too old now
  25. Greetings everyone, I hope you have a wonderful day. I came up with a couple of issues trying to make my (very first) GSAP-based website, and I'm lost at sea. I want to apologize if my method are wrongs, and I'd gladly hear from you guys if you have any advice on to how you'd tackle this puzzle. First of all, I needed my sections to be pinned in place. For this, I looped in my containers and created a scrollTrigger for each of them, and took some extra room for the end, based to the initial height of the elements (100vh). It was mainly to give some time for the next container to get pinned before the first one would go away. for (let i = 0; i < containerArray.length; i++) { ScrollTrigger.create({ trigger: containerArray[i], pin: containerArray[i], pinSpacing: false, id: "pin"+containerArray[i], start: 'top top', end: '150% top', markers: true }); } One of my issue for this first part is, my first section is scrollable for 125% of the height of the viewport (which works as intended coded like that), but my other sections are scrollable for only 100% (because it's also how my code should work). Is there a better method to overlap sections while keeping the scrollable height identical and logical based on the height of the elements ? ----------------------------------- Onto the next part, that's probably where I started to make many mistakes. Now that I had a window in which both my current and next containers were on screen and pinned, I needed to insert a scrollTrigger between the moment the next container was pinned, and the current container was unpinned to trigger my animations. So I created an other scrollTrigger for each inner section, with a start and end value of 125% (which is 25% below the moment the next container is pinned, and 25% above the current container is unpinned. Used this method mainly to ensure the animation plays after the next container is in place and before the current container goes away.) For those specific scrollTriggers, and with the onLeave and onEnterBack methods, I add and remove a couple of classes, mainly to prevent sections to overlap even if they are hidden and keep allowing users to interact with the visible section (classes active / inactive) and changing the BG color of the body (to match the sections color). And after all that, I added my animation in the timeline. for (let i = 0; i < sectionArray.length; i++) { let tl = gsap.timeline({ scrollTrigger: { trigger: sectionArray[i], toggleActions: "restart none reverse none", start: '125% top', end: '125% top', id: 'animate '+containerArray[i]+" & "+containerArray[i+1], markers: true, onLeave: () => { document.querySelector(containerArray[i]).classList.add("inactive"); document.querySelector(containerArray[i]).classList.remove("active"); if(bgColor[i+1]){ document.querySelector("body").classList.add(bgColor[i+1]); document.querySelector("body").classList.remove(bgColor[i]); document.querySelector(containerArray[i+1]).classList.add("active"); document.querySelector(containerArray[i+1]).classList.remove("inactive"); } }, onEnterBack: () => { document.querySelector(containerArray[i]).classList.add("active"); document.querySelector(containerArray[i]).classList.remove("inactive"); if(bgColor[i+1]){ document.querySelector("body").classList.add(bgColor[i]); document.querySelector("body").classList.remove(bgColor[i+1]); document.querySelector(containerArray[i+1]).classList.remove("active"); document.querySelector(containerArray[i+1]).classList.add("inactive"); } } } }); //Animation that should happen right in between the pin of next container, //and the unpin of current container if(containerArray[i+1] !== "undefined") { tl.to(sectionArray[i], { alpha: 0, duration: 0.2 }) tl.from(sectionArray[i+1], { alpha: 0, duration: 0.2 }) } } It somehow works, but only if no resize is done and if we scroll slowly. When I resize, it seems to display wrong things (despite the scrollbar not moving at all since it's mainly opening the console and resizing horizontally?) and I have no idea how to resolve that. When I scroll too fast, the same thing happens. But I thing I know where it comes from. Probably from the fact each section has a scrollTrigger bound to said section, and the one after it (called with [i] and [i+1]), which means triggering multiple scrollTrigger at the same time basically asks for the same section to be animated "to" alpha 0 and "from" alpha 0 at the same time, but I have no idea how to fix that... I also can't seem to prevent the last scrollTrigger to appear, but that's probably just me being too deep into it that I can't find the solution that is right under my nose, haha ! I hope my code isn't a mess, I hope I've been clear enough for you to be able to give me some guidance. Thanks for reading, and have a good day ! Nelou.
×
×
  • Create New...