I have an svg
which forms the basis of my horizontal
scroller.
Within this svg
, I have added the class .animate
to the elements which I want to fade in up as the item comes into view. The .animate class for reference has been added to all the text items in the svg
.
Currently, only the .animate
elements that are in view initially fade in up. When I scroll down to continue the scroller, the other elements are static. They're not fading in or translating
up or down in any way?
TL;DR, here is what I'm trying to achieve:
.horizontalScroller__intro
..horizontalScroller__intro
has faded away, start the horizontal scroll for .horizontalScroller__items
.animate
in my scroller will fade in up to its original position.Note: I understand SO rules and preferences to post code here. But, my demo's contain a length SVG, which I cannot post here as it exceeds SO's character limit.
Here is a demo of my latest approach
From the scrollTrigger docs, containerAnimation
is what helps achieve animations on horizontal scrollers, and is what I've tried to achieve.
However, in my demo above, I have the following issues:
.horizontalScroller__intro
doesn't show initially, when it should, and should fade out on scroll..animate
elements that are in view, do not fade in upIf I use timeline
(see below snippet), then the intro fade out and scroller works. But, doesn't animate in the child elements, which is where I need containerAnimation
$(function() {
let container = document.querySelector(".horizontalScroller__items");
let tl = gsap.timeline({
scrollTrigger: {
trigger: ".horizontalScroller",
pin: ".horizontalScroller",
anticipatePin: 1,
scrub: true,
invalidateOnRefresh: true,
refreshPriority: 1,
end: '+=4000px',
markers: true,
}
});
tl.to('.horizontalScroller__intro', {
opacity: 0,
})
tl.to(container, {
x: () => -(container.scrollWidth - document.documentElement.clientWidth) + "px",
ease: "none",
})
});
I'm struggling to find a way in which I can make the intro fade in, the scroller scroll horizontally, and the .animate
elements to fade in, or fade in up.
Edit:
@onkar ruikar, see notes based on your sandbox below:
.animate
elements to scroll up into view (currently, once the text fade away, and then the horizontal scroller starts working, only then does the .animate
that are suppose to be in view, fade in up.animate
elements have loaded, the next .animate
elements that are part of the scroller, they do not fade in up. They're static. As each .animate
element comes into view, then it should fade in up (I think it's currently triggering once, for all the elements).See visual here:
In the above gif, you can see the first two text blocks are hidden, as soon as they're in view, I want them to fade up. Then the 3rd and 4th text blocks are static, when they should fade up as the user scrolls to that section.
You need to use onUpdate
method on the scroll trigger.
onUpdate: self => console.log("progress", self.progress)
Based on the self.progress
set opacity, x position etc.
Full demo on codesandbox. Click on "Open Sandbox" button on bottom right to see the code.
if ("scrollRestoration" in history) {
history.scrollRestoration = "manual";
}
$(function() {
let container = document.querySelector(".horizontalScroller__items");
let elements = gsap.utils.toArray(
document.querySelectorAll(".animate")
);
let intro = document.querySelector(".horizontalScroller__intro");
let svg = document.querySelector("svg");
let animDone = false;
window.scrollPercent = -1;
var scrollTween = gsap.to(container, {
ease: "none",
scrollTrigger: {
trigger: ".horizontalScroller",
pin: ".horizontalScroller",
anticipatePin: 1,
scrub: true,
invalidateOnRefresh: true,
refreshPriority: 1,
end: "+=600%",
markers: true,
onEnter: (self) => {
moveAnimate();
},
onLeaveBack: (self) => {
resetAnimate();
},
onUpdate: (self) => {
let p = self.progress;
if (p <= 0.25) {
let op = 1 - p / 0.23;
intro.style.opacity = op;
animDone = false;
}
if (p > 0.23) {
moveAnimate();
// we do not want to shift the svg by 100% to left
// want to shift it only by 100% - browser width
let scrollPercent =
(1 - window.innerWidth / svg.scrollWidth) * 100;
let shift = ((p - 0.22) * scrollPercent) / 0.78;
gsap.to(svg, {
xPercent: -shift
});
}
}
}
});
function resetAnimate() {
gsap.set(".animate", {
y: 150,
opacity: 0
});
}
resetAnimate();
function moveAnimate() {
for (let e of elements) {
if (ScrollTrigger.isInViewport(e, 0.4, true))
gsap.to(e, {
y: 0,
opacity: 1,
duration: 2
});
}
}
});
You need to set opacity 0 on .animate
elements in CSS. And use end: '+=400%'
instead of 4000px. Relative dimensions can be used in position based calculations easily.