Тайминг анимаций и UX-восприятие
1) Почему тайминг критичен
Анимация — это не «украшение», а манипуляция временем восприятия. Миллисекунды влияют на:- чувство мгновенного отклика и доверие к системе;
- ясность причин-следственных связей (откуда/куда переместился элемент);
- утомляемость и комфорт в длительных сессиях;
- точность действий (особенно на мобильных и при высоких ставках).
Правило: тайминг служит смыслу. Если анимация не помогает понять «что произошло», она мешает.
2) Психофизика и пороги
Ориентиры для продуктового UI:- ≤ 50 мс — эхо ввода (печать, клик-эффект); кажется мгновенным.
- ≤ 100 мс — первый визуальный фидбек по действию (кнопка «нажалась»).
- 120–180 мс — hover/focus, «мягкий» переход состояния.
- 180–280 мс — модалки/панели; воспринимается как «естественное» появление.
- 300–500 мс — внимательное перемещение (shared element), прогресс «шаг вперед».
- ≈ 1200–1600 мс — цикл skeleton/shimmer; дольше — утомляет.
3) Кривые ускорения (easing) и «вес»
Элемент «с весом» стартует быстрее и «прилипает» в конце. Базовые кривые:- Стандарт: `cubic-bezier(0.2, 0, 0.2, 1)` — нейтральная «материальная» динамика.
- Ускорение (pressed): `cubic-bezier(0.4, 0, 1, 1)` — быстрый вход, короткий клик.
- Замедление (overlay out): `cubic-bezier(0, 0, 0.2, 1)` — мягкий выход.
- Подчеркнутый акцент (редко): `cubic-bezier(0.2, 0.8, 0.2, 1.2)` с overshoot ≤ 8 px.
Оптика веса: чем больше компонент (карточка, дроуэр), тем длиннее длительность (+40–80 мс к базовой).
4) Фазы и хореография
Разделяйте движение на фазы:1. Инициация (10–40 мс): легкий fade/scale 0.98→1 — сигнал начала.
2. Транспорт (основная фаза): перемещение/раскрытие.
3. Осадка (20–60 мс): небольшой тормоз, стабилизация тени/кольца фокуса.
Каскад (stagger):- Списки: 20–40 мс/элемент, максимум 6–8 элементов подряд.
- Формы: без каскада; все появляется одновременно, чтобы не мешать вводу.
Обратимость: «назад» зеркалит «вперед» и быстрее на 15–30%.
5) Тайминги по типам взаимодействий
6) Восприятие времени: как «ускорить» без реального ускорения
Instant affordance: мгновенная смена cursors/pressed-стиля ≤ 100 мс еще до сети.
Сокрытие сложности: параллелите загрузки; фоновое подтягивание данных до открытия панели.
Смысловой якорь: shared element и направление движения уменьшают когнитивную стоимость ожидания.
Оптимистичные обновления: UI «готов» сразу, сервер подтверждает или откатывает.
7) Утомляемость и гигиена анимаций
Избегайте бесконечных пульсаций; любой цикл должен быть прерывистым или отключаемым.
Микроэффекты на массивах элементов (таблица, грид) делайте без blur/box-shadow на каждом узле.
Поддерживайте `prefers-reduced-motion: reduce`: оставляйте только fade ≤ 100 мс или статичный переключатель состояния.
css
@media (prefers-reduced-motion: reduce) {
{ animation: none! important; transition-duration:.01ms! important; }
}
8) Токены таймингов (дизайн-система)
json
{
"motion": {
"duration": { "press": 90, "hover": 160, "focus": 160, "overlayIn": 240, "overlayOut": 180, "tab": 200, "shared": 280 },
"easing": {
"standard": "cubic-bezier(0. 2,0,0. 2,1)",
"accelerate": "cubic-bezier(0. 4,0,1,1)",
"decelerate": "cubic-bezier(0,0,0. 2,1)"
},
"stagger": { "listItem": 30, "maxItems": 8 }
}
}
Именование: `motion.duration.{role}` и `motion.easing.{role}` — единые для движка компонентов и Figma.
9) Реализация: CSS и Framer Motion
CSS-пресеты:css
:root{
--dur-press:90ms; --dur-hover:160ms; --dur-overlay-in:240ms; --dur-overlay-out:180ms;
--ease-std:cubic-bezier(.2,0,.2,1);
--ease-acc:cubic-bezier(.4,0,1,1);
--ease-dec:cubic-bezier(0,0,.2,1);
}
.button{ transition: transform var(--dur-press) var(--ease-acc), box-shadow var(--dur-hover) var(--ease-std); }
.button:active{ transform: scale(.98); }
.modal-enter{ animation: modalIn var(--dur-overlay-in) var(--ease-std) both; }
.modal-exit { animation: modalOut var(--dur-overlay-out) var(--ease-dec) both; }
@keyframes modalIn{ from{opacity:0; transform:translateY(16px) scale(.98)} to{opacity:1; transform:none} }
@keyframes modalOut{ from{opacity:1} to{opacity:0; transform:translateY(8px) scale(.99)} }
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}} exit={{opacity:0}}
transition={{duration:.18, ease:[0. 2,0,0. 2,1]}} className="fixed inset-0 bg-black/50">
<motion. div initial={{y:16, scale:.98, opacity:0}}
animate={{y:0, scale:1, opacity:1, transition:{duration:.24, ease:[0. 2,0,0. 2,1]}}}
exit={{y:8, scale:.99, opacity:0, transition:{duration:.18, ease:[0,0,0. 2,1]}}}
className="m-auto max-w-lg rounded-2xl bg-white p-6">
{children}
</motion. div>
</motion. div>
)}
</AnimatePresence>
);
}
10) Композиция времени: параллель vs последовательность
Параллель (fade + translate одновременно) — быстрее по ощущению.
Последовательность (сначала контейнер, затем контент) — яснее структуру, но дольше. Применяйте, когда важно показать иерархию.
Избегайте «ступенек» > 60 мс между тесно связанными элементами в одном блоке.
11) Тайминг и контент
Текст: не анимируйте letter/word-by-word в продуктах; это маркетинговая техника.
Числа/счетчики: шаг 40–60 мс батчами, без дрожания layout (tabular-nums).
Графики: раскрытие серии 180–240 мс, hover-highlight ≤ 120 мс.
12) Доступность и ошибка восприятия
Фокус-стили должны появляться без задержки.
Предупреждения/ошибки — анимация минимальная (≤ 120 мс), без тряски, если пользователь с AT (assistive tech).
Избегайте вспышек > 3/с и больших контрастных мерцаний.
13) Специфика iGaming
Ставка/покупка:- Press ≤ 100 мс; статус `busy` сразу; итоговый тост/индикатор — без задержек.
- Тайминг отклика UI важнее анимации подтверждения: подтверждение короткое 120–160 мс.
- Старт ≤ 200 мс, равномерный цикл, торможение 300–500 мс; никаких бесконечных мерцаний.
- Win-всплеск ≤ 500 мс, без строба; текст суммы — AAA.
- Обновления батчами (250–1000 мс); визуальный дифф ≤ 160 мс; без скачков макета.
- На hover/focus — дебаунс подсветки 80–120 мс, чтобы не «мигало».
14) Анти-паттерны
Линейные кривые для перемещений (ощущение «механичности»).
Длительности > 400 мс для простых состояний кнопки.
Каскад 100+ мс по списку из десятков элементов (тягомотина).
Тени/blur на сотнях элементов в анимации.
Несогласованность: одинаковые действия с разными таймингами в одном продукте.
Отложенный фокус или задержка на активацию по клавиатуре.
15) QA-чек-лист таймингов
Консистентность
- Тайминги и кривые берутся из токенов, одинаковы для одинаковых действий.
Отклик
- Press/hover/focus укладываются в шкалу 80–180 мс.
- Первый визуальный отклик ≤ 100 мс.
Хореография
- Вход и выход симметричны; выход быстрее входа на 15–30%.
- Каскад не превышает 8 элементов и 40 мс шаг.
A11y
- `prefers-reduced-motion` поддержан; фокус без задержки.
- Нет миганий > 3/с.
Перформанс
- Анимируются только `transform/opacity`; нет массовых blur/теней.
16) Документация в дизайн-системе
«Motion Tokens»: duration/easing/stagger + карта применений (button, overlay, tab, list).
«Rhythm & Phasing»: схемы каскада и обратимости.
«Reduce Motion»: правила деградации и примеры.
«Do/Don’t»: короткие клипы с таймкодами и целевыми метриками (INP/First Feedback).
Краткое резюме
Хороший тайминг — это мгновенный отклик, понятная хореография и экономные кривые. Держите короткие длительности для микро-состояний, растягивайте только там, где это добавляет смысла, поддерживайте reduce-motion и не анимируйте «дорогие» свойства. Тогда интерфейс ощущается живым и надежным — особенно в сценариях реального времени и высоких ставок.