Một giao diện cao cấp (Award-winning Website) thường tạo được ấn tượng mạnh mẽ ngay trong 3 giây đầu tiên nhờ vào những chuyển động tinh tế (Micro-interactions) và hiệu ứng cuộn trang mượt mà.
Tuy nhiên, việc lạm dụng animation không đúng cách có thể gây tụt khung hình (Jank) và làm nặng CPU. Bài viết này hướng dẫn cách kết hợp hợp lý giữa **Framer Motion** (cho tương tác component) và **GSAP ScrollTrigger** (cho hiệu ứng cuộn phức tạp) với hiệu năng 60 FPS chuẩn chỉ.
1. Phân chia vai trò: Framer Motion vs GSAP
Không nên xem Framer Motion và GSAP là hai đối thủ đối đầu, mà hãy tận dụng thế mạnh riêng của từng thư viện:
- Framer Motion: Tuyệt vời cho các tương tác gắn liền với vòng đời component React: hover, tap, exit animations (
AnimatePresence), stagger children, layout animations (layoutId). - GSAP (GreenSock) + ScrollTrigger: Lựa chọn số 1 cho các chuỗi timeline phức tạp, pin cố định màn hình (Sticky Scroll), scrubbing animation theo thanh cuộn chuột, và điều khiển chuyển động SVG/Canvas.
2. Micro-interactions với Framer Motion
Tạo hiệu ứng spring physics tự nhiên cho các nút bấm và card:
"use client";
import { motion } from "framer-motion";
export function InteractiveCard({ title, desc }: { title: string; desc: string }) {
return (
<motion.div
whileHover={{ y: -6, scale: 1.02 }}
whileTap={{ scale: 0.98 }}
transition={{ type: "spring", stiffness: 400, damping: 25 }}
className="p-6 rounded-2xl bg-zinc-900 border border-zinc-800 hover:border-emerald-500/40 cursor-pointer shadow-lg transition-colors"
>
<h4 className="text-lg font-bold text-zinc-100 mb-2">{title}</h4>
<p className="text-sm text-zinc-400 leading-relaxed">{desc}</p>
</motion.div>
);
}3. Sticky Scroll & Pinning với GSAP ScrollTrigger
Hiệu ứng ghim cố định một phần tử trong khi người dùng tiếp tục cuộn nội dung (như showcase danh mục dự án nổi bật):
"use client";
import { useEffect, useRef } from "react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
export function StickyProjects() {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const ctx = gsap.context(() => {
gsap.to(".project-card", {
scrollTrigger: {
trigger: containerRef.current,
start: "top top",
end: "+=2000",
scrub: 1, // Làm mượt chuyển động theo quán tính chuột
pin: true, // Ghim lại màn hình
},
rotateY: 15,
opacity: 1,
stagger: 0.2,
});
}, containerRef);
return () => ctx.revert(); // Dọn dẹp animation khi unmount
}, []);
return (
<section ref={containerRef} className="min-h-screen flex items-center justify-center">
<div className="project-card opacity-0 bg-zinc-900 p-8 rounded-3xl border border-zinc-800">
<h3 className="text-2xl font-bold">Featured Showcase</h3>
</div>
</section>
);
}Facing similar challenges?
I can help you optimize your website — reach out for a free consultation.
Kết luận
Animation đẹp là animation phục vụ cho trải nghiệm người dùng, giúp giao diện có linh hồn nhưng không gây cảm giác khó chịu. Hãy cân bằng giữa tính thẩm mỹ và hiệu năng để tạo nên những sản phẩm cuốn hút nhất.
Want to discuss further?
If you have specific questions about web performance, React, or want to collaborate on a project — reach out directly.