Framer Motion vs CSS Animations
Cover photo by Sebastian Svenson on Unsplash
Do you need Framer Motion for your site animations? Probably not, but it sure makes things easier when complexity scales.
The CSS approach
Native CSS is fast. It doesn’t bloat your bundle, and the browser handles it efficiently on the compositor thread. If I need a simple hover effect or a basic fade, I write CSS.
.box { transition: transform 0.3s ease;}.box:hover { transform: scale(1.1);}It’s great. But once you need to orchestrate sequences (like items appearing one after another), CSS starts to fight you. You end up calculating delay variables or writing messy keyframes.
The Framer Motion way
Framer Motion gives you a declarative API. You define the state, and it handles the transition. When I have a list that needs to reorder smoothly or a component that mounts and unmounts with specific exit animations, this is my go-to tool.
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}/>“But isn’t this overkill for small projects?” A reader might ask. You’re right. Adding a heavy dependency for a simple pulse effect is a bad move. If your project is mostly static, stick to CSS.
The trade-offs
I’ve seen developers use Framer Motion for everything, leading to massive JavaScript execution times (especially on low-end mobile devices). CSS is objectively better for performance-critical simple animations. Framer Motion is for when you’re building complex, state-driven UI interactions where syncing DOM nodes feels like a nightmare.
Sometimes I’m not even sure if my animation logic is truly efficient, especially when dealing with layout shifts. Measuring performance in a real production environment is hard, and I often wonder if I’m over-engineering the user experience just because I like the way the code looks.
My verdict
Start with CSS. If the logic involves complex sequences or exit states that require significant boilerplate, pull in Framer Motion. Don’t be afraid to keep it simple. Are you optimizing for developer velocity or raw load time?