Moritz L Posted June 6, 2023 Share Posted June 6, 2023 Hi there! This is a StackBlitz of a minimal demo showing two routes that I want to transition between: https://stackblitz.com/edit/sveltejs-kit-template-default-2zmrub?file=src%2Froutes%2F%2Blayout.svelte The transition should be a simple wipe from bottom to top – meaning the old page is wiping away and revealing the new page underneath. Sounds simple, but I'm struggling with implementation. Without the transition, everything works just fine. But when I work on the transition, I have the following problems: 1. During transition, Svelte puts the HTML of the new page next to the HTML of the old page. Since I am transitioning the <main> element, we have two <main> elements in the DOM for a short period of time. I want to keep the "old page" on top of everything. So I am using gsap.set to absolutely position the "old page" on top of everything and then animating the height property to reveal the "new page" underneath. Afterwards, Sveltekit unmounts the "old page". The positioning already works as you can see in the demo (after clicking the nav link, the "old page" stays there for 2 seconds before the new page becomes visible). But the wipe doesn't. If I am animating autoAlpha instead, it does work. 2. When I scroll down the page a bit and then clicking the link, the content is jumping up to the top of the page and then animating to the new page. Is this a Sveltekit behavior? Or GSAP? I tried window.scrollTo to the value of window.scrollY just before animating but that did not work (it did work without ScrollSmoother, though). 3. The SmoothScroll doesn't work after route change. Weirdly, this works on my local project which is setup the same way. 4. There is a gap at the end of the page and I don't know where it comes from. I should add that I got the transition working without SmoothScroller. And I got SmoothScroller working without the transition. Just together, everything falls apart. So my best guess is, it has something to do with absolutely positioning the elements, since SmoothScroller uses a fixed element as a wrapper. Pushing me in the right direction would already help me tremendously. I can then figure out the details. Thanks so much! Link to comment Share on other sites More sharing options...
Solution Moritz L Posted June 6, 2023 Author Solution Share Posted June 6, 2023 I solved my issue when I completely refactored how I implemented scroll trigger. I moved all the logic to +layout.svelte like so: <script> import '../app.css' import { gsap } from 'gsap' import { ScrollSmoother } from 'gsap/dist/ScrollSmoother' import { ScrollTrigger } from 'gsap/dist/ScrollTrigger' import BaseNav from '$lib/components/base-nav.svelte' import { onMount } from 'svelte' export let data /** * @type {ScrollSmoother} */ let smoother if (typeof window !== 'undefined') { gsap.registerPlugin(ScrollTrigger, ScrollSmoother) } onMount(() => { smoother = ScrollSmoother.create({ smooth: 1, effects: false }) }) /** * @param {HTMLElement} node * @param {Object} options * @param {number} [options.duration] * @param {number} [options.delay] */ // out transition function wipe(node, { duration = 250, delay = 0 }) { // pulling "from" page out of document flow and positioning it absolutely over "to" page gsap.set(node, { position: 'fixed', inset: 0, width: '100%', height: window.innerHeight, zIndex: 9999, overflow: 'hidden', backgroundColor: '#fff', opacity: 1, visibility: 'visible' }) // prevent scrollY from jumping to top of page gsap.set(node.firstChild, { y: -window.scrollY }) // make sure "to" page is scrolled to top smoother.scrollTop(0) const tl = gsap.timeline({ delay, defaults: { duration: duration / 1000 } }) tl.to(node, { height: 0, ease: 'power4.inOut' }) return { duration, delay, /** * The function to call on each animation frame. * @param {number} t - The current tick value. */ tick: (t) => { tl.progress(1 - t) } } } </script> <BaseNav /> <div id="smooth-wrapper"> <div id="smooth-content"> {#key data.url.pathname} <main out:wipe={{ duration: 2000 }} on:outroend={() => ScrollTrigger.refresh()}> <slot /> </main> {/key} </div> </div> I hope that helps anyone who tries to work with Svelte transitions and ScrollSmoother. 3 Link to comment Share on other sites More sharing options...
Rodrigo Posted June 6, 2023 Share Posted June 6, 2023 Hi @Moritz L, Is great to hear that you were able to solve your issue 🥳 Finally thank you for sharing your solution with the community 💚 Let us know if you have any other question. Happy Tweening! Link to comment Share on other sites More sharing options...
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