Scrolltrigger Animation, GSAP, ELementor
Create stacked cards with floating animation in Elementor
SHARE
Get the custom CODE for my tutorial:
GSAP/Javascript Code:
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>
<script>
const cardsContainer = document.querySelector('.cards');
const cards = document.querySelectorAll('.card');
cards.forEach((card, index) => {
const cardInner = card.querySelector('.card__inner');
// Check if the card is the last in the array
const isLastCard = index === cards.length - 1;
// Random rotation between -5 and +5 degrees
const rotation = gsap.utils.random(-5, 5, true);
// Set initial values for scale and filter
gsap.set(cardInner, {
scale: 1, // Set initial scale
filter: 'brightness(1)', // Set initial brightness
rotation: rotation // Initial rotation
});
// First ScrollTrigger for scaling and rotation
ScrollTrigger.create({
trigger: card,
start: 'top 100%', // Scaling starts when the card reaches the middle of the viewport
end: 'top 25%', // Scaling ends when the card reaches 25% of the viewport
scrub: 1, // Sync the animation with scrolling
onUpdate: (self) => {
const progress = self.progress;
// Scale and rotate the card
gsap.to(cardInner, {
scale: gsap.utils.interpolate(1.2, 0.9, progress), // Scale from 1.2 to 0.9
rotation: rotation, // Maintain the rotation
overwrite: false // No overwrite to avoid conflicts
});
}
});
// Second ScrollTrigger for dimming the previous card
ScrollTrigger.create({
trigger: card,
start: 'top 75%', // The new card dims the previous one when it reaches 75% of the viewport
end: 'top 50%', // Dimming ends when the top of the card reaches 50% of the viewport
scrub: 1, // Sync the dimming with scrolling
onUpdate: (self) => {
const progress = self.progress;
// Dim the previous card (if available)
if (index > 0) { // Check if there is a previous card
const previousCardInner = cards[index - 1].querySelector('.card__inner');
gsap.to(previousCardInner, {
filter: `brightness(${gsap.utils.interpolate(1, 0.5, progress)})`, // Dimming the previous card
overwrite: false // No overwrite to avoid conflicts
});
}
}
});
// Floating effect for the cards
gsap.to(cardInner, {
y: '+=20', // Slight floating upwards
repeat: -1, // Infinite loop
yoyo: true, // Move back and forth
ease: 'power1.inOut', // Smooth transitions
duration: gsap.utils.random(1, 2), // Random duration between 1 and 2 seconds
overwrite: false // No overwrite to avoid conflicts
});
});
</script>
CSS:
Put this into your Elementor Custom CSS or in your main container on the page
.card {
position: sticky !important;
top: 15vh;
height: 70vh;
}
@media (max-width: 768px) {
.card {
position: sticky;
top: 15vh;
height: 70vh;
}}
@media (max-width: 480px) {
.card {
position: sticky;
top: 15vh;
height: 70vh;
}}