Motion-дизайн и анимации интерфейсов
1) Зачем анимация в продукте
Анимация — это навигация во времени. Она:- объясняет причинно-следственные связи (куда исчез, откуда появился элемент),
- направляет внимание на главное действие,
- подтверждает результат (feedback) и уменьшает когнитивную нагрузку,
- делает переходы предсказуемыми и «осязаемыми».
Правило №1: смысл > стиль. Любая анимация отвечает на вопрос «что произошло и как это связано со мной?».
2) Базовые принципы
1. Иерархия движения: первыми двигаются контейнеры, затем содержимое, затем детали.
2. Постоянство: одинаковые паттерны для одинаковых действий.
3. Экономия: минимум свойств, минимум кадров; лучше короче и яснее.
4. Реалистичная физика: ускорение в начале, замедление в конце; отсутствуют «рывки».
5. Обратимость: «назад» ощущается зеркально «вперед».
6. Доступность: уважайте системные настройки снижения анимации.
3) Длительности и кривые (рекомендации)
3.1 Длительности (desktop / mobile)
Hover: 120–180 мс
Focus/Pressed: 80–120 мс
Tooltip/Toast: вход 180–240 мс, выход 120–160 мс
Модалки/дроуэры: 200–320 мс
Переходы экранов: 240–360 мс
Скролл-привязки/параллакс: ≤ 200 мс на сегмент, избегать бесконечных циклов
3.2 Кривые
Основная: `cubic-bezier(0.2, 0.0, 0.2, 1)` — естественный «материальный» темп
Вход быстрее, выход мягче: `cubic-bezier(0.05, 0.7, 0.1, 1)`
Упругость (редко, акцент): `cubic-bezier(0.2, 0.8, 0.2, 1.2)` с ограничением overshoot ≤ 8px/8°
Правило: не используйте линейную интерполяцию для перемещений и opacity одновременно — ощущение «механичности».
4) Хореография переходов
Появление: легкий масштаб 0.98→1.0 + fade-in, смещение 8–16 px по оси возникновения.
Исчезновение: обратный порядок, быстрее входа (−20–30%).
Перелистывание/смена вкладок: общее «основание» (контейнер) сдвигается на 16–24 px; активная вкладка подсвечивается до начала движения.
Списки: ослабляйте каскад (stagger 20–40 мс/элемент, не более 6–8 элементов).
5) Микро-взаимодействия (patterns)
Кнопка (hover/press): тень + легкий подскрол/scale 0.98; pressed отскакивает ≤ 80 мс.
Фокус: контрастное кольцо без blur; анимируйте толщину/прозрачность, а не glow.
Инпуты: каретка/подсветка поля на focus; ошибки — встряхивание ≤ 6 px, ≤ 140 мс, 1 цикл.
Toggle/Checkbox: снап до конечного положения, задержка клика не более 60–80 мс.
Скелетон/загрузка: shimmer 1200–1600 мс, амплитуда яркости ≤ 20%, без резких вспышек.
6) Состояния контента
Loading → Success/Empty/Error: один «канал» движения; не смешивайте разные направления.
Toast/Alerts: прилетают из стороны источника события (например, снизу-справа для действий пользователя).
Pull to refresh: растяжение с упругим отпружиниванием; время возврата ≤ 250 мс.
7) Доступность (A11y) и безопасность
Поддерживайте `prefers-reduced-motion: reduce`: заменяйте перемещения на fade/scale ≤ 1% или статичный переход.
Избегайте вспышек > 3 в секунду и больших контрастных миганий (фотосенситивная эпилепсия).
Не используйте сильный параллакс/зум у пользователей с историей укачивания; делайте опцию отключения.
Фокус-стили всегда видимы без анимации (не только цвет/движение).
8) Производительность (60 FPS как цель)
Анимируйте только opacity и transform (translate/scale/rotate); избегайте `top/left/width/height`.
Включайте композитинг: `transform: translateZ(0)` или `will-change: transform, opacity` (умеренно).
Минимизируйте repaint: не анимируйте тени с большим blur и фильтры на множестве элементов.
Разбивайте большие переходы на батчи; используйте requestAnimationFrame.
Для списков — виртуализация/переразметка вне экрана.
9) Токены motion в дизайн-системе
json
{
"motion": {
"duration": { "xs": 100, "sm": 160, "md": 220, "lg": 280, "xl": 340 },
"easing": {
"standard": "cubic-bezier(0. 2, 0. 0, 0. 2, 1)",
"emphasis": "cubic-bezier(0. 05, 0. 7, 0. 1, 1)",
"decelerate": "cubic-bezier(0. 0, 0. 0, 0. 2, 1)",
"accelerate": "cubic-bezier(0. 4, 0. 0, 1, 1)"
},
"stagger": { "listItem": 30, "maxItems": 8 }
}
}
Именование: `motion.{duration|easing|stagger}.{role}` — `hover`, `focus`, `overlayIn`, `pageTransition`, `listItem`.
10) Реализация (CSS/JS/React)
CSS-переменные:css
:root {
--motion-dur-sm: 160ms;
--motion-dur-md: 220ms;
--motion-ease: cubic-bezier(0. 2, 0, 0. 2, 1);
}
@media (prefers-reduced-motion: reduce) {
{ animation: none! important; transition-duration: 0. 01ms! important; }
}
Компонент (Framer Motion, пример):
tsx import { motion, AnimatePresence } from "framer-motion";
export function Modal({ open, children }) {
return (
<AnimatePresence>
{open && (
<motion. div initial={{ opacity: 0 }}
animate={{ opacity: 1, transition: { duration: 0. 22 } }}
exit={{ opacity: 0, transition: { duration: 0. 16 } }}
className="fixed inset-0 bg-black/50"
>
<motion. div initial={{ y: 16, scale: 0. 98, opacity: 0 }}
animate={{ y: 0, scale: 1, opacity: 1, transition: { duration: 0. 24, ease: [0. 2,0,0. 2,1] } }}
exit={{ y: 8, scale: 0. 99, opacity: 0, transition: { duration: 0. 18 } }}
className="m-auto max-w-lg rounded-2xl bg-white p-6"
>
{children}
</motion. div>
</motion. div>
)}
</AnimatePresence>
);
}
Lottie/SVG: используйте для иллюстративных пустых состояний и onboarding; не для критичных контролов. Оптимизируйте и кэшируйте.
11) Паттерны загрузки
Skeleton вместо спиннера там, где известна структура контента.
Progress: детерминированный бар, если известен прогресс; индетерминированный — с равномерным темпом, без «рывков».
Избегайте «плавающих» skeleton при перестроении — закрепляйте размеры.
12) Переходы между страницами/экранами
Сохраняйте точку внимания (shared element transitions) — карточка «раскрывается» в деталь.
Навигация «вглубь» идет вперед/вправо/вверх, «назад» — обратно; направление едино для платформы.
Фоновая подложка затемняется до 40–60% при оверлеях.
13) Специфика iGaming
Spin / Reveal: один короткий разгон (≤ 200 мс) + равномерное вращение + мягкое затухание; запрет на бесконечные циклы без действия.
Win/Jackpot: всплеск света ≤ 500 мс, без строба; дубль звуком на низкой громкости; текст победы читабелен (AAA по контрасту).
Турниры/рейтинги: инкремент счета — счетчик с табличными цифрами и легким шагом 40–60 мс/единицу (батчами), без «скачков» layout.
Ответственная игра: уведомления и лимиты без отвлекающих эффектов; анимация минимальная, акцент на читабельность.
14) Анти-паттерны
Задержки > 120 мс до отклика на клик.
«Лифт» из opacity+scale 0.9→1.05→1.0 с overshoot на каждую мелочь.
Параллакс фона, конфликтующий со скроллом.
Бесконечные мерцания/пульсации.
Анимация свойств layout/paint (`height`, `left`, `filter: blur()`) на множестве элементов.
Непостоянные кривые и длительности у одинаковых действий.
15) Процесс и QA
В дизайне:- Прототипы с таймингами/кривыми; хореография на уровне фреймов.
- Каталог motion-токенов и примеры для компонентов.
- Юнит-тесты видимости/состояний (переходы завершаются как ожидается).
- Визуальные тесты (снапшоты конца анимаций).
- Профилирование (Performance/Timeline) на сценах с максимальной нагрузкой.
- Поддержан `prefers-reduced-motion`.
- Только transform/opacity.
- Длительности и кривые соответствуют токенам.
- Нет вспышек > 3/сек и сильного строба.
- Skeleton вместо спиннера, где возможно.
- Переходы обратимы и предсказуемы.
16) Документация в дизайн-системе
«Motion-токены»: duration/easing/stagger с примерами.
«Паттерны переходов»: модалки, списки, вкладки, страницы.
«A11y & Performance»: гайд по reduce-motion и композитингу.
«Do/Don’t»: короткие клипы с удачными/неудачными примерами.
Краткое резюме
Motion-дизайн — это язык причин и следствий. Держите тайминги короткими, кривые согласованными, а свойства — дешевыми для рендера. Уважайте доступность, документируйте токены и проверяйте производительность. Тогда анимация усилит UX и не помешает скорости и ясности интерфейса.