Создание микроанимаций элементов интерфейса сайта

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Создание микроанимаций элементов интерфейса сайта
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Создание микроанимаций элементов интерфейса сайта

Микроанимации — это визуальная обратная связь на уровне отдельных элементов: нажатая кнопка, загружающийся список, переключённый тоггл, появившееся уведомление. Они делают интерфейс «живым» и снижают когнитивную нагрузку: пользователь видит, что его действие зарегистрировано.

Принципы

Продолжительность. Микроанимации — 100–300ms. Медленнее — раздражает. Быстрее — незаметно. Исключение: анимации с физическим смыслом (spring-эффект, inertia) могут быть длиннее.

Easing. ease-out для появлений (быстрый старт, плавное торможение — имитирует реальные объекты). ease-in для исчезновений. spring для интерактивных элементов.

Не анимировать то, что не менялось. Если пользователь кликнул кнопку и ничего не изменилось логически — анимация лжёт.

Кнопки

Самая частая микроанимация. Три уровня:

CSS-only (hover + active):

.btn {
  transition: transform 120ms ease-out, box-shadow 120ms ease-out;
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(0,0,0,0.15);
}

.btn:active {
  transform: translateY(0) scale(0.98);
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

Loading state (кнопка с spinner):

const Button: React.FC<ButtonProps> = ({ children, onClick, loading }) => {
  return (
    <button
      onClick={onClick}
      disabled={loading}
      className={`btn ${loading ? 'btn--loading' : ''}`}
    >
      <AnimatePresence mode="wait">
        {loading ? (
          <motion.span
            key="spinner"
            initial={{ opacity: 0, scale: 0.5 }}
            animate={{ opacity: 1, scale: 1 }}
            exit={{ opacity: 0, scale: 0.5 }}
            transition={{ duration: 0.15 }}
          >
            <SpinnerIcon />
          </motion.span>
        ) : (
          <motion.span
            key="label"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
          >
            {children}
          </motion.span>
        )}
      </AnimatePresence>
    </button>
  );
};

Success state (кнопка → галочка → текст «Сохранено»):

type BtnState = 'idle' | 'loading' | 'success';

const SaveButton: React.FC = () => {
  const [state, setState] = useState<BtnState>('idle');

  const handleClick = async () => {
    setState('loading');
    await saveData();
    setState('success');
    setTimeout(() => setState('idle'), 2000);
  };

  return (
    <motion.button
      onClick={handleClick}
      animate={state === 'success' ? { backgroundColor: '#22c55e' } : {}}
      transition={{ duration: 0.3 }}
    >
      {state === 'idle'    && 'Сохранить'}
      {state === 'loading' && <Spinner />}
      {state === 'success' && <><CheckIcon /> Сохранено</>}
    </motion.button>
  );
};

Форма: появление ошибок и успеха

// Поле с анимированной ошибкой
const FormField: React.FC<{ error?: string }> = ({ error, ...props }) => (
  <div className="field">
    <input {...props} className={error ? 'input--error' : ''} />
    <AnimatePresence>
      {error && (
        <motion.p
          key="error"
          initial={{ opacity: 0, y: -4, height: 0 }}
          animate={{ opacity: 1, y: 0,  height: 'auto' }}
          exit={{ opacity: 0,   y: -4,  height: 0 }}
          transition={{ duration: 0.2 }}
          className="field__error"
        >
          {error}
        </motion.p>
      )}
    </AnimatePresence>
  </div>
);

Shake-анимация при невалидном submit:

const shakeVariants = {
  idle:  { x: 0 },
  shake: { x: [0, -10, 10, -8, 8, -4, 4, 0] },
};

<motion.form
  variants={shakeVariants}
  animate={hasErrors ? 'shake' : 'idle'}
  transition={{ duration: 0.5, ease: 'easeInOut' }}
>

Тоггл / Чекбокс

const Toggle: React.FC<{ checked: boolean; onChange: () => void }> = ({ checked, onChange }) => (
  <button
    role="switch"
    aria-checked={checked}
    onClick={onChange}
    className="toggle"
  >
    <motion.div
      className="toggle__thumb"
      animate={{ x: checked ? 20 : 0 }}
      transition={{ type: 'spring', stiffness: 500, damping: 30 }}
    />
  </button>
);

Spring-переход (stiffness: 500, damping: 30) даёт физически правдоподобное движение с лёгким отскоком.

Список: появление элементов

const listVariants = {
  hidden: {},
  visible: { transition: { staggerChildren: 0.05 } },
};

const itemVariants = {
  hidden:  { opacity: 0, y: 20 },
  visible: { opacity: 1, y: 0, transition: { duration: 0.3 } },
};

const AnimatedList: React.FC<{ items: Item[] }> = ({ items }) => (
  <motion.ul
    variants={listVariants}
    initial="hidden"
    animate="visible"
  >
    {items.map(item => (
      <motion.li key={item.id} variants={itemVariants}>
        <ItemCard item={item} />
      </motion.li>
    ))}
  </motion.ul>
);

staggerChildren: 0.05 — каждый следующий элемент появляется с задержкой 50ms. Для 20 элементов — весь список раскрывается за 1 секунду, что воспринимается как плавный каскад.

Toast-уведомления

const ToastNotification: React.FC<{ message: string; type: 'success' | 'error' }> = ({ message, type }) => (
  <motion.div
    className={`toast toast--${type}`}
    initial={{ opacity: 0, y: 50, scale: 0.9 }}
    animate={{ opacity: 1, y: 0,  scale: 1 }}
    exit={{ opacity: 0, y: 20, scale: 0.95, transition: { duration: 0.15 } }}
    transition={{ type: 'spring', stiffness: 400, damping: 25 }}
  >
    {type === 'success' ? <CheckCircleIcon /> : <AlertIcon />}
    <span>{message}</span>
  </motion.div>
);

Тост появляется снизу-вверх со spring-эффектом и уходит быстро (duration: 0.15) — это важно, уходить должно быстрее, чем появляться.

Число с анимацией инкремента

Для счётчиков, статистики, корзины:

const AnimatedNumber: React.FC<{ value: number }> = ({ value }) => {
  const spring = useSpring(value, { stiffness: 100, damping: 30 });
  const display = useTransform(spring, Math.round);

  return <motion.span>{display}</motion.span>;
};

Число «накручивается» к новому значению физически плавно.

Курсорные эффекты (Spotlight, Magnetic)

// Magnetic button — тянется к курсору
const MagneticButton: React.FC<ButtonProps> = ({ children }) => {
  const ref = useRef<HTMLButtonElement>(null);
  const x = useMotionValue(0);
  const y = useMotionValue(0);

  const handleMouseMove = (e: React.MouseEvent) => {
    const rect = ref.current!.getBoundingClientRect();
    const centerX = rect.left + rect.width / 2;
    const centerY = rect.top + rect.height / 2;
    x.set((e.clientX - centerX) * 0.3);
    y.set((e.clientY - centerY) * 0.3);
  };

  const handleMouseLeave = () => { x.set(0); y.set(0); };

  return (
    <motion.button
      ref={ref}
      style={{ x, y }}
      transition={{ type: 'spring', stiffness: 200, damping: 15 }}
      onMouseMove={handleMouseMove}
      onMouseLeave={handleMouseLeave}
    >
      {children}
    </motion.button>
  );
};

Производительность

Анимировать можно только transform и opacity — эти свойства не вызывают reflow. Анимация width, height, top, left бьёт по FPS:

/* Плохо */
.card { transition: width 300ms; }

/* Хорошо */
.card { transition: transform 300ms; }
.card:hover { transform: scaleX(1.05); }

В framer-motion layout prop автоматически анимирует изменение размеров через FLIP-технику (сначала замеряет финальное состояние, потом анимирует transform от начального к конечному).

Сроки

Задача Время
Кнопки (hover, active, loading, success) 0.5 дня
Формы (валидация, shake, успех) 0.5 дня
Список stagger + toast 0.5 дня
Toggle, чекбоксы, анимированные числа 0.5 дня
Продвинутые эффекты (magnetic, spotlight) 1 день