Reset GSAP ScrollSmoother
after Barba transition
Used technologies:
The problem
After implementing a basic GSAP ScrollSmoother instance you'll notice that after a Barba page transition the page won't scroll back to the top or won't scroll at all.
That is because Barba has shown a new container over the current one and didn't refresh after the new content appeared.
In the Barba lifecycle in between the `afterLeave` and `afterEnter` events 2 page containers live in the DOM together.
Hiding next Barba container
Before the next container is shown I hide it so the DOM won't contain 2 containers and thereby increasing the height of the body. The next container will be overlapping the current one but will be hidden. As so:
gsap.set(data.next.container, { position: "fixed", inset: "0", zIndex: "-1" });
This can be reset by clearing the set props (assuming it doesnt contain any self-created inline styling)
gsap.set(data.next.container, {clearProps: 'all'});
Killing ScrollSmoother
The target here is to reset the ScrollSmoother instance, by scrolling to the top, killing it and recreating it.
I have seen multiple implementations of killing all ScrollTrigger instances but that won't be enough.
Because ScrollSmoother can only be created once you have to get that instance first before using it, as followed:
var sm = ScrollSmoother.get();
sm.scrollTo(0);
sm.kill();
Resetting ScrollTrigger
IF you are using ScrollTrigger's in your GSAP animations it is also useful to reset those.
Recreating them on the next container is fine but the previous ScrollTrigger instances won't be deleted so a lot of instances will be created or duplicated.
To delete those, I use this snippet:
let triggers = ScrollTrigger.getAll();
triggers.forEach( trigger => {
trigger.kill();
});
Final result
Putting it all together:
import barba from '@barba/core';
import { gsap, ScrollTrigger, ScrollSmoother } from "./gsap.js";
barba.init({
prevent: ({ el, href }) => href == '#',
transitions: [{
beforeEnter(data) {
const done = this.async();
// 1. animate current container and disappear
gsap.to(data.current.container, {
opacity: 0,
duration: 0.3,
onComplete: () => {
gsap.set(data.next.container, { position: "fixed", inset: "0", zIndex: "-1" }); // hide next container behind current one
data.current.container.remove();
// Remove all GSAP Scroll triggers or we get 'em duplicated
let triggers = ScrollTrigger.getAll();
triggers.forEach( trigger => {
trigger.kill();
});
// Get the current ScrollSmoother instance and 'reset' it
var sm = ScrollSmoother.get();
sm.scrollTo(0);
sm.kill();
// Recreating the ScrollSmoother
ScrollSmoother.create({
smooth: 1, // how long (in seconds) it takes to "catch up" to the native scroll position
effects: true, // looks for data-speed and data-lag attributes on elements
smoothTouch: 0.1, // much shorter smoothing time on touch devices (default is NO smoothing on touch devices)
});
done();
}
});
},
enter(data) {
gsap.set(data.next.container, {clearProps: 'all'}); // remove z-index from next container (previously added)
},
afterEnter(data) {
const done = this.async();
// load init javascript here before content is loaded
// // 4. show the next container fading in and trigger next event
gsap.to(data.next.container, {
opacity: 1,
duration: 0.7,
onComplete: function() {
done();
},
});
}
}]
});
Let's get in touch
And we'll see from there
Collaboration?
Start a project?
You name it...
Contact me at
hello@luukthe.dev