
UI-анимации — это не только про красоту, но и про восприятие, структуру и даже скорость. В этой статье рассматриваются популярные фреймворки для создания анимаций в интерфейсах: CSS, Framer Motion, GSAP и Motion One. Сравнение проводится на реальных кейсах с кодом, примерами и субъективным мнением, где каждый инструмент показывает свои сильные и слабые стороны. В конце — небольшие выводы и неожиданные результаты.
Когда «просто появляется» уже не работает
Пару лет назад дизайнер принес макет с комментарием: «Вот тут кнопка должна мягко появляться, как облако, а потом улетать, как мыльный пузырь». Я кивнул, но подумал: «Это тебе не After Effects». Сегодня такие вещи вполне достижимы прямо в браузере — и с минимальными потерями по производительности. Вопрос в другом: чем именно это делать?
Чтобы разобраться, я взял 4 инструмента, с которыми чаще всего сталкивался в боевых и личных проектах:
-
CSS-анимации
-
GSAP
-
Framer Motion (для React)
-
Motion One (от создателей Framer Motion, но в Vanilla JS)
И сравнил их на трех простых, но показательных кейсах:
-
Анимация появления элемента
-
Анимация наведения
-
Анимация между состояниями (shared element transition)
Кейсы и код
Кейc 1. Плавное появление карточки
CSS (чистый подход)
.card { opacity: 0; transform: translateY(20px); transition: opacity 0.4s ease, transform 0.4s ease; } .card.visible { opacity: 1; transform: translateY(0); }
<div class="card">Контент</div> <script> document.querySelector('.card').classList.add('visible'); </script>
GSAP
import gsap from "gsap"; gsap.fromTo(".card", { opacity: 0, y: 20 }, { opacity: 1, y: 0, duration: 0.4, ease: "power2.out" } );
Framer Motion (React)
<motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.4, ease: "easeOut" }} > Контент </motion.div>
Motion One
import { animate } from "motion"; animate(".card", { opacity: [0, 1], transform: ["translateY(20px)", "translateY(0)"] }, { duration: 0.4, easing: "ease-out" });
Вывод:
CSS — просто и быстро, но ограничено. GSAP — супергибкий, особенно когда нужна последовательность анимаций. Framer Motion — прекрасно работает в React, почти магия. Motion One — гибкий и легкий, но ещё не так широко поддержан.
Кейc 2. Hover-анимации: реакция без тормозов
CSS (старый-добрый способ)
.button { transition: transform 0.3s ease; } .button:hover { transform: scale(1.05); }
Framer Motion
<motion.button whileHover={{ scale: 1.05 }} transition={{ type: "spring", stiffness: 300 }} > Нажми меня </motion.button>
GSAP с событиями
const btn = document.querySelector('.button'); btn.addEventListener("mouseenter", () => { gsap.to(btn, { scale: 1.05, duration: 0.3 }); }); btn.addEventListener("mouseleave", () => { gsap.to(btn, { scale: 1, duration: 0.3 }); });
Комментарий:
CSS — самый производительный, потому что GPU делает всё сам. Но когда нужна упругая, резиновая, «живущая» анимация — тут лучше справляются GSAP или Framer Motion. Особенно Framer: hover-анимации с «spring» — кайф.
Кейc 3. Shared element transition: переход между состояниями
Это прям боль, особенно если нужно, чтобы элемент «переезжал» из одного экрана в другой. Типичная история в e-commerce: кликаешь на товар, карточка «перелетает» в детальную страницу — не исчезает и появляется заново, а плавно трансформируется.
Framer Motion (Layout animations в React)
На главной странице с карточками товаров:
<Link to={`/product/${id}`}> <motion.div layoutId={`product-image-${id}`} className="product-card"> <img src="item.jpg" alt="item" /> <p>Супертовар</p> </motion.div> </Link>
На детальной странице:
<motion.div layoutId={`product-image-${id}`} className="product-detail"> <img src="item.jpg" alt="item" /> <h2>Супертовар</h2> <p>Описание товара, характеристики и прочее</p> </motion.div>
Ключевой момент: layoutId
должен совпадать. Тогда Framer Motion сам вычисляет позицию и размер обоих элементов, и делает плавный переход между ними при навигации.
GSAP Flip Plugin (для Vanilla JS или любой библиотеки)
<div class="product-card" data-id="123"> <img src="item.jpg" /> </div>
import { Flip } from "gsap/Flip"; const card = document.querySelector(".product-card"); const detail = document.querySelector(".product-detail"); const state = Flip.getState(card); detail.appendChild(card); // перемещаем DOM-элемент Flip.from(state, { duration: 1, ease: "power1.inOut" });
Комментарий:
Фреймер — магия без боли. Но работает только в пределах React и требует чуть понимания AnimatePresence
. GSAP с Flip — пушка, но требует настройки и оплаты. CSS здесь, честно говоря, просто не справляется.
Маленькие неожиданности
-
GSAP идеально подходит для длинных цепочек и сложных последовательных анимаций. Особенно когда всё строится динамически.
-
Framer Motion ощущается как нативный язык анимаций в React.
-
Motion One — легковесная альтернатива, которая приятно удивляет.
-
CSS — быстрый и надёжный, но ограниченный.
А что по производительности?
Я сделал несколько замеров через Chrome DevTools и увидел, что…
-
CSS и Motion One — лидеры по FPS и плавности.
-
Framer Motion — чуть тяжелее, но приемлемо.
-
GSAP — самый тяжелый, особенно при множестве элементов, но и самый мощный.
Итого
Универсального ответа нет. Всё зависит от задачи:
-
Нужно просто и быстро? CSS
-
Анимация в React-приложении? Framer Motion
-
Сложные переходы и динамика? GSAP
-
Минимализм и гибкость? Motion One
Если вы делаете сложные интерфейсы, обязательно посмотрите, что происходит под капотом. Плавность — это не «вау», это структурный элемент восприятия. И она не должна быть случайной.
Хочешь примеры этих кейсов в CodeSandbox или Stackblitz? Пиши в комментариях — с радостью поделюсь.
ссылка на оригинал статьи https://habr.com/ru/articles/900664/
Добавить комментарий