React Animasyon: Framer Motion Rehberi

React Animasyon: Framer Motion Rehberi
Animasyonlar, kullanıcı deneyimini zenginleştiren ve arayüzün canlı hissettiren önemli bir unsurdur. Framer Motion, React için en güçlü ve kullanımı en kolay animasyon kütüphanesidir. Deklaratif API'si sayesinde karmaşık animasyonları bile birkaç satır kodla oluşturabilirsiniz. Bu rehberde, Framer Motion'ın temellerinden ileri düzey tekniklere kadar her şeyi ele alacağız.
Neden Framer Motion?
Framer Motion, CSS animasyonlarının ve diğer JS kütüphanelerinin karmaşıklığını ortadan kaldırır. Layout animasyonları, gesture desteği, AnimatePresence ile exit animasyonları ve spring physics gibi özellikleriyle öne çıkar. API tasarımı React'in deklaratif yapısıyla mükemmel uyum sağlar.
Temel Animasyonlar
// npm install framer-motion
import { motion } from 'framer-motion';
// Basit bir fade-in animasyonu
function FadeIn({ children }: { children: React.ReactNode }) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, ease: 'easeOut' }}
>
{children}
</motion.div>
);
}
// Hover ve tap animasyonları
function AnimatedButton({ children, onClick }: { children: React.ReactNode; onClick: () => void }) {
return (
<motion.button
onClick={onClick}
whileHover={{ scale: 1.05, boxShadow: '0 5px 15px rgba(0,0,0,0.2)' }}
whileTap={{ scale: 0.95 }}
transition={{ type: 'spring', stiffness: 400, damping: 17 }}
className="bg-blue-600 text-white px-6 py-3 rounded-lg font-medium"
>
{children}
</motion.button>
);
}
// Scroll tetiklemeli animasyon
function ScrollReveal({ children }: { children: React.ReactNode }) {
return (
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-100px' }}
transition={{ duration: 0.6 }}
>
{children}
</motion.div>
);
}
type: 'spring' transition'ı doğal ve fiziksel animasyonlar oluşturur. stiffness (sertlik) ve damping (sönümleme) değerlerini ayarlayarak animasyonun karakterini belirleyebilirsiniz.
Variants ile Orchestrated Animasyonlar
Variants, birden fazla animasyon durumunu tanımlayıp, parent-child ilişkisiyle otomatik olarak sıralanmasını sağlar. Bu özellik, staggered (kademeli) animasyonlar oluşturmak için idealdir.
import { motion } from 'framer-motion';
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1, // Her child 0.1s arayla animasyona başlar
delayChildren: 0.2,
},
},
};
const itemVariants = {
hidden: { opacity: 0, x: -20 },
visible: {
opacity: 1,
x: 0,
transition: { type: 'spring', stiffness: 100 },
},
};
interface MenuItem {
id: string;
label: string;
icon: string;
}
function AnimatedMenu({ items }: { items: MenuItem[] }) {
return (
<motion.ul
variants={containerVariants}
initial="hidden"
animate="visible"
className="space-y-2"
>
{items.map((item) => (
<motion.li
key={item.id}
variants={itemVariants}
className="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-100 cursor-pointer"
>
<span>{item.icon}</span>
<span>{item.label}</span>
</motion.li>
))}
</motion.ul>
);
}
// Kullanım
function Sidebar() {
const menuItems: MenuItem[] = [
{ id: '1', label: 'Ana Sayfa', icon: '🏠' },
{ id: '2', label: 'Ürünler', icon: '📦' },
{ id: '3', label: 'Siparişler', icon: '📋' },
{ id: '4', label: 'Ayarlar', icon: '⚙️' },
];
return <AnimatedMenu items={menuItems} />;
}
AnimatePresence: Exit Animasyonları
import { motion, AnimatePresence } from 'framer-motion';
import { useState } from 'react';
interface Notification {
id: string;
message: string;
type: 'success' | 'error' | 'info';
}
function NotificationStack() {
const [notifications, setNotifications] = useState<Notification[]>([]);
const addNotification = (type: Notification['type'], message: string) => {
const id = crypto.randomUUID();
setNotifications((prev) => [...prev, { id, message, type }]);
// 3 saniye sonra otomatik kaldır
setTimeout(() => {
setNotifications((prev) => prev.filter((n) => n.id !== id));
}, 3000);
};
const removeNotification = (id: string) => {
setNotifications((prev) => prev.filter((n) => n.id !== id));
};
const typeColors = {
success: 'bg-green-500',
error: 'bg-red-500',
info: 'bg-blue-500',
};
return (
<div className="fixed top-4 right-4 space-y-2 z-50">
<AnimatePresence>
{notifications.map((notification) => (
<motion.div
key={notification.id}
initial={{ opacity: 0, x: 300, scale: 0.8 }}
animate={{ opacity: 1, x: 0, scale: 1 }}
exit={{ opacity: 0, x: 300, scale: 0.8 }}
transition={{ type: 'spring', stiffness: 200, damping: 20 }}
className={`${typeColors[notification.type]} text-white px-4 py-3 rounded-lg shadow-lg flex items-center gap-3 min-w-[300px]`}
>
<span className="flex-1">{notification.message}</span>
<button onClick={() => removeNotification(notification.id)} className="text-white/80 hover:text-white">
✕
</button>
</motion.div>
))}
</AnimatePresence>
{/* Demo butonları */}
<div className="fixed bottom-4 right-4 space-x-2">
<button onClick={() => addNotification('success', 'İşlem başarılı!')} className="bg-green-600 text-white px-3 py-1 rounded">Başarı</button>
<button onClick={() => addNotification('error', 'Bir hata oluştu!')} className="bg-red-600 text-white px-3 py-1 rounded">Hata</button>
</div>
</div>
);
}
Layout Animasyonları
import { motion, LayoutGroup } from 'framer-motion';
import { useState } from 'react';
function FilterableTabs() {
const [activeTab, setActiveTab] = useState('all');
const tabs = ['all', 'design', 'development', 'marketing'];
return (
<div className="flex gap-2 p-1 bg-gray-100 rounded-lg">
{tabs.map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className="relative px-4 py-2 rounded-md text-sm font-medium"
>
{activeTab === tab && (
<motion.div
layoutId="active-tab"
className="absolute inset-0 bg-white rounded-md shadow"
transition={{ type: 'spring', stiffness: 300, damping: 30 }}
/>
)}
<span className="relative z-10">{tab}</span>
</button>
))}
</div>
);
}
layoutScroll ve layoutDependency prop'larını kullanarak optimizasyon yapın.
Sonuç
Framer Motion, React uygulamalarınıza profesyonel animasyonlar eklemenin en kolay ve en güçlü yoludur. Basit fade/slide animasyonlarından karmaşık layout geçişlerine, gesture desteğinden exit animasyonlarına kadar geniş bir yelpaze sunar. Variants ile orchestrated animasyonlar, AnimatePresence ile mount/unmount geçişleri ve layoutId ile otomatik layout animasyonları oluşturabilirsiniz. Animasyonları kullanıcı deneyimini iyileştirmek için kullanın, abartmayın.