Review

Parallax hero with CSS scroll-driven animation

The winery estate landing page janks on mid-range phones when the vineyard backdrop tracks scroll. Drop the scroll listener / rAF offset loop and drive the hero parallax with CSS scroll-driven animations so the compositor owns the work.

ReactTier 1cssperformancefrontend

Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.

src/marketing/EstateHero.tsx+6-20
1414export function EstateHero({ estate }: { estate: Estate }) {
15- const [offsetY, setOffsetY] = useState(0);
16-
17- useEffect(() => {
18- let frame = 0;
19- const onScroll = () => {
20- cancelAnimationFrame(frame);
21- frame = requestAnimationFrame(() => setOffsetY(window.scrollY * 0.35));
22- };
23- window.addEventListener("scroll", onScroll, { passive: true });
24- return () => {
25- cancelAnimationFrame(frame);
26- window.removeEventListener("scroll", onScroll);
27- };
28- }, []);
2915
3016 return (
3117 <section className="estate-hero relative h-[70vh] overflow-hidden">
32- <img
33- src={estate.coverUrl}
34- alt=""
35- className="absolute inset-0 h-[120%] w-full object-cover"
36- style={{ transform: `translate3d(0, ${offsetY}px, 0)` }}
37- />
18+ <img
19+ src={estate.coverUrl}
20+ alt=""
21+ className="estate-hero__parallax absolute inset-0 h-[120%] w-full object-cover"
22+ /* animation-timeline: scroll(); drives translateY without JS */
23+ />
3824 <div className="relative z-10 flex h-full flex-col justify-end p-8 text-white">
3925 <h1 className="font-serif text-4xl">{estate.name}</h1>
4026 <p className="mt-2 max-w-lg text-white/80">{estate.tagline}</p>
4127 </div>
4228 </section>
4329 );
4430}