Hello,
Newbie with React and Gsap here.
I have just made my first portfolio website and encountered an issue.
I have a projects section and a contact form section to which I have applied scroll trigger animations where the projects' cards and the form appear on scroll (simple opacity animation, nothing too fancy).
Basically all the animations work fine when scrolling down slowly/in a normal way, but if from the top I scroll down fast (even just a few lines), all the animations are triggered all together.
The projects' card are rendered from a parent component, let me know if a snippet of this one is required too.
Code snippets below.
Projects' cards
import { LuGithub, LuArrowRight } from "react-icons/lu";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/all";
import { useEffect, useRef } from "react";
import data from "../data/projectData";
const ProjectCard = (props) => {
const { image, title, description, link, repo, id, alt } = props;
const img = useRef();
const buttonLink = useRef();
const buttonGit = useRef();
gsap.registerPlugin(ScrollTrigger);
useEffect(() => {
let tl = gsap.timeline({
scrollTrigger: {
trigger: img.current,
start: "top 95%",
},
});
tl.to(img.current, { autoAlpha: 1, duration: 3 });
});
useEffect(() => {
let tl = gsap.timeline({
scrollTrigger: {
trigger: buttonLink.current,
start: "top 95%",
},
});
tl.to(buttonLink.current, {
autoAlpha: 1,
duration: 0.5,
ease: "power3.out",
delay: -0.2,
});
tl.to(buttonGit.current, {
autoAlpha: 1,
duration: 0.5,
ease: "power3.out",
});
});
return (
<div
className={`${
id === data.length
? "md:flex md:flex-col md:justify-center md:items-center md:mx-auto"
: ""
} mb-14`}
>
<div
className=" mt-10 mb-4 w-[95%] mx-auto relative group shadow-projects-shadow hover:shadow-none transition-shadow duration-300 opacity-0 rounded-md overflow-hidden "
ref={img}
>
<img
alt={alt}
src={image}
className="group-hover:blur-[8px] group-hover:opacity-40 group-hover:transition-all group-hover:duration-300 group-hover:ease-out group-hover:scale-[.98]"
loading="lazy"
/>
<div className="absolute left-[5%] bottom-[5%] w-4/5 ">
<h2 className="text-secondary text-sm sm:text-xl md:text-lg uppercase opacity-0 font-bold group-hover:opacity-100 group-hover:transition-all group-hover:duration-1000 group-hover:ease-out mb-8 xl:text-xl">
{title}
</h2>
<p className="text-additional text-xs sm:text-lg md:text-sm opacity-0 group-hover:opacity-100 group-hover:transition-all group-hover:duration-1000 group-hover:ease-out xl:text-lg">
{description}
</p>
</div>
</div>
<div className="w-[95%] mx-auto flex items-center justify-center gap-[20%] sm:gap-[30%] ">
<a href={link} target="_blank" rel="noreferrer">
<button
className="projects-buttons group duration-500 text-lg sm:text-xl lg:text-lg xl:text-2xl"
ref={buttonLink}
>
Link{" "}
<LuArrowRight className="projects-button__icon text-lg sm:text-xl lg:text-lg xl:text-2xl" />
</button>
</a>
<a
aria-label="github"
href={repo}
target="_blank"
rel="noreferrer"
ref={buttonGit}
className="opacity-0"
>
<LuGithub className="projects-button__icon hover:text-white hover:scale-105 transition-all duration-300 text-lg sm:text-xl lg:text-lg xl:text-2xl" />
</a>
</div>
</div>
);
};
export default ProjectCard;
and lastly the form's snippet
import React, { useRef, useEffect } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/all";
const Contact = () => {
const [result, setResult] = React.useState("");
const onSubmit = async (event) => {
event.preventDefault();
setResult("Sending....");
const formData = new FormData(event.target);
formData.append("access_key", "4359a0b1-14fd-4278-b15b-c45673a1d9dc");
const res = await fetch("https://api.web3forms.com/submit", {
method: "POST",
body: formData,
}).then((res) => res.json());
if (res.success) {
setResult(res.message);
} else {
setResult(res.message);
}
};
const contacts = useRef();
gsap.registerPlugin(ScrollTrigger);
useEffect(() => {
gsap.fromTo(
contacts.current,
{
autoAlpha: 0,
},
{
autoAlpha: 1,
duration: 1.5,
ease: "power1.inOut",
scrollTrigger: {
trigger: contacts.current,
start: "top 90%",
},
}
);
}, []);
return (
<section id="contact">
<div
className=" sm:max-w-[70%] sm:mx-auto lg:flex lg:mt-16 lg:gap-16 lg:items-center"
ref={contacts}
>
<h3 className="text-center text-secondary mt-12 mb-8 font-bold text-xl md:text-2xl lg:mt-0 px-4 sm:px-0 xl:text-3xl font-PrimaryF lg:font-SecondaryF">
Have you got a project in mind? Let's talk
</h3>
<form
onSubmit={onSubmit}
className="w-4/5 mx-auto rounded-lg px-8 py-4 mb-12 shadow-3xl sm:max-w-[65%] lg:max-w-[50%]"
>
<label
htmlFor="name"
className="text-secondary pl-2 font-PrimaryF relative"
aria-label="name"
>
<input
type="text"
id="name"
className="form-input"
placeholder="Name"
required
/>
</label>
<label
htmlFor="email"
aria-label="email"
className="text-secondary pl-2 font-PrimaryF -translate-x-8"
>
<input
type="email"
id="email"
className="form-input"
placeholder="Email"
required
/>
</label>
<label htmlFor="textarea" aria-label="textaread">
<textarea
id="textarea"
name="Text"
className="form-input mt-8"
placeholder="Message"
></textarea>
</label>
<input
type="submit"
className="text-secondary bg-transparent border-2 border-secondary px-8 py-1 rounded-lg block mx-auto hover:bg-secondary hover:text-additional
transition-all duration-300 font-PrimaryF mb-8 mt-12"
aria-label="submit"
/>
<span className=" text-secondary mx-auto text-center block">
{result}
</span>
</form>
</div>
</section>
);
};
export default Contact;
Thanks in advance for any help or suggestion provided
PS: I know I should have posted a CodePen demo, but it has proved very difficult to create for me.