Motion: анимации в React без боли

#react#animation#javascript#ui

Последние три проекта подряд я сталкиваюсь с одной и той же проблемой: дизайнер приносит сложные анимации, а в коде это превращается в ад из setTimeout и CSS-классов. Framer Motion хорош, но иногда слишком тяжеловесен. На этом фоне motiondivision/motion выглядит любопытной альтернативой — библиотека набрала 130 звёзд за неделю и позиционируется как «современный подход к анимациям».

Что внутри коробки

Motion предлагает декларативный API, похожий на Framer Motion, но с несколькими ключевыми отличиями:

  1. Только необходимый runtime — нет лишних зависимостей, сборка весит ~8kb gzipped
  2. Spring-анимации из коробки с физически точными параметрами
  3. Оптимизация под React 18+ с приоритизацией анимаций в concurrent mode

Базовый пример выглядит знакомо:

import { motion } from 'motiondivision';

function Box() {
  return (
    <motion.div
      animate={{ x: 100 }}
      transition={{ type: 'spring', stiffness: 300 }}
    >
      Push me
    </motion.div>
  );
}

Но под капотом есть интересные решения. Например, анимации работают через Web Animations API, где доступно, с fallback на requestAnimationFrame.

Где motion реально выручает

На практике библиотека показала себя хорошо в трёх сценариях:

  1. Комплексные последовательности анимаций
    Вместо цепочек then/catch можно использовать ключ sequence:

    <motion.div
      animate={{
        x: [0, 100, 0],
        opacity: [1, 0.5, 1]
      }}
      transition={{
        sequence: [0, 0.2, 0.1] // задержки для каждого шага
      }}
    />
    
  2. Синхронизация с прокруткой
    Есть встроенная поддержка ScrollTrigger-подобного поведения без дополнительных зависимостей:

    <motion.section
      scroll={{ start: 0, end: 100 }}
      animate={{
        scale: [1, 1.2, 1],
        backgroundColor: ['#fff', '#000', '#fff']
      }}
    />
    
  3. Анимации по данным
    Особенно удобно при работе с диаграммами или визуализациями:

    const variants = {
      hidden: { opacity: 0 },
      visible: (i) => ({
        opacity: 1,
        transition: { delay: i * 0.1 }
      })
    };
    
    items.map((item, i) => (
      <motion.li
        custom={i}
        variants={variants}
      />
    ))
    

Подводные камни

После недели использования в продакшн-проекте нашлось несколько нюансов:

  1. Документация сыровата — некоторые API описаны поверхностно, приходится лезть в исходники
  2. Мало примеров с SVG — для иконок и сложных путей пока лучше GSAP
  3. Нет DevTools как у Framer Motion — отладка анимаций через console.log

Самый болезненный момент — ограниченная поддержка Server-Side Rendering. На Next.js с SSG пришлось добавлять костыли для гидратации.

Кому стоит попробовать

Motion — не серебряная пуля, но хороший выбор для:

Лично я оставил его в своём стеке для небольших проектов, где не нужна вся мощь GSAP. Главное преимущество — библиотека не пытается сделать всё, а решает конкретные задачи анимации UI. Если вам нужно просто оживить интерфейс без перегрузки bundle — стоит дать motion шанс.


Источник: https://github.com/motiondivision/motion