Эффекты наведения и интерактивность
1) Роль наведения в UX
Hover/press/focus — это язык обратной связи. Пользователь должен мгновенно понимать:- «Это интерактивно?» (наведение/курсор/подсветка),
- «Где я?» (фокус-стиль),
- «Что произойдет по клику?» (состояние и affordance),
- «Получилось ли действие?» (active/pressed и последующий feedback).
Принцип: эффекты усиливают смысл, а не заменяют его. Ключевая информация и доступ к действию не должны быть скрыты только за наведением.
2) Модель состояний и семантика
Базовый набор: `default` → `hover` → `focus` → `active/pressed` → `disabled` → `loading` (опционально).
Для ссылок добавляем `visited`, для переключателей — `checked`.
- Между состояниями — визуальная разница формой/толщиной/иконкой, а не только цветом.
- Контраст текста/иконок к фону: ≥ 4.5:1 (обычный текст), ≥ 3:1 (крупный/жирный).
- Фокус виден без наведения (клавиатура/скринридер).
3) Устройства и медиа-запросы
Не все имеет hover. Планируйте интерактивность под разные типы ввода:css
/ There is an exact pointer and hover (mouse/trackpad )/
@ media (hover: hover) and (pointer: fine) {/hover effects/}
/ No hover or rough pointer (touch/remote control )/
@ media (hover: none), (pointer: coarse) {/alternatives to hover/}
/ Any type of pointer (hybrid devices )/
@ media (any-hover: hover) {/minimal improvements/}
Правила:
- На тач-устройствах эффекты наведения не критичны для обнаружения действия — используйте явные affordances: цвет/иконка/рамка/подсказка.
- Не прячьте навигацию/контролы только «под hover».
4) Длительности и кривые
Коротко и предсказуемо:- Hover: 120–180 мс
- Focus: 120–180 мс
- Active/Pressed: 80–120 мс
- Ripple/ink (если используется): ≤ 240 мс, 1 цикл
Кривая по умолчанию: `cubic-bezier(0.2, 0, 0.2, 1)`
Active — быстрее (`cubic-bezier(0.4, 0, 1, 1)`), выход — мягче (`cubic-bezier(0, 0, 0.2, 1)`).
5) Токены дизайн-системы (пример)
json
{
"interactive": {
"duration": { "hover": 160, "focus": 160, "active": 90 },
"easing": { "std": "cubic-bezier(0. 2,0,0. 2,1)", "acc": "cubic-bezier(0. 4,0,1,1)" },
"shadow": { "hover": "var(--elev-2)", "focus": "0 0 0 3px var(--focus-ring)" },
"opacity": { "disabled": 0. 38, "muted": 0. 64 }
}
}
6) Кнопки: эталонный паттерн
Default: читаемый текст ≥ 4.5:1 к заливке.
Hover: −ΔL фона 0.02–0.04, легкая тень, курсор `pointer`.
Active: еще −ΔL 0.02–0.04, укороченная тень/вдавливание (scale 0.98), длит. 80–100 мс.
Focus: контрастное кольцо 2–3 px без blur.
Disabled: курсор `not-allowed`/`default`, opacity ≤ 0.38, никаких hover-эффектов.
css
.button {
transition: background-color. 16s var(--ease), transform. 09s var(--ease-acc), box-shadow. 16s var(--ease);
}
@media (hover:hover) and (pointer:fine) {
.button:hover { background: var(--btn-bg-hover); box-shadow: var(--shadow-hover); }
}
.button:active { transform: scale(.98); }
.button:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
.button[disabled] { opacity:.38; pointer-events: none; }
7) Ссылки и текстовые действия
Различимость не только цветом: подчеркивание по умолчанию или на hover/focus.
Для наведения: усиление подчеркивания (толщина/offset), легкое изменение тона.
`Visited` — другой оттенок той же палитры, контраст сохранен.
css a { text-decoration: underline; text-underline-offset:.12em; }
@media (hover:hover) and (pointer:fine) {
a:hover { text-underline-offset:.2em; }
}
a:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }
8) Карточки, списки, таблицы
Карточки:- Hover: мягкая тень/подсветка рамки, курсор `pointer` только если кликабельно вся карточка.
- Active: короткое вдавливание, подсветка заголовка.
- Focus: видимое кольцо вокруг карточки, не только внутри.
- Hover-фон с ΔL 0.02–0.04; активная строка — четкая рамка.
- Клики по строке допустимы только при явном affordance (иконка «→», подсказка).
- Старательно ограничивайте «лесенку» из каскадных задержек — максимум 6–8 элементов (stagger 20–30 мс).
9) Формы и поля ввода
Hover у полей: тонкая подсветка рамки (ΔL ~0.05), без изменения размера блока.
Focus: контрастное кольцо + изменение цвета рамки; placeholder остается различимым (≥ 3:1).
Ошибка: цвет + иконка/текст; короткое «shake» допустимо ≤ 6 px, ≤ 140 мс, один раз.
10) Иконки и маленькие цели
Увеличивайте зону клика до 32×32 (desktop) / 40×40 (mobile), даже если сама иконка 20–24 px.
Hover: смена непрозрачности/заливки/толщины, не более 1–2 свойств.
Active: краткий «snap» по scale 0.98.
Focus: кольцо по контейнеру зоны клика.
11) Доступность (A11y) и клавиатура
Поддерживайте `:focus-visible` (для мыши фокус-стили не показываем, для клавиатуры — показываем).
Элементы, создающие hover-подсказки, обязаны иметь эквивалент по фокусу (тот же контент появляется по клавише Tab/Enter).
Aria-атрибуты: у интерактивов есть `role`, `aria-pressed`/`aria-expanded`/`aria-current` по ситуации.
Prefers-reduced-motion: заменяем масштаб/сдвиг на минимум (opacity/fill), отключаем пульсации.
css
@media (prefers-reduced-motion: reduce) {
{ transition-duration:.01ms! important; animation: none! important; }
}
12) Производительность
Анимируйте только `opacity` и `transform`; избегайте `width/height/left/top`, тяжелых blur/теней на множестве элементов.
Умеренно используйте `will-change`; убирайте после окончания перехода.
На списках/таблицах — минимальные эффекты, без «глобальных» repaint.
13) Hover-intent и «липкость»
На десктопе уменьшайте ложные hover-триггеры:- Порог задержки 80–120 мс перед показом сложного tooltip/меню.
- «Липкость» курсора: если пользователь движется от пункта к меню под углом, даем 200–300 мс «коридора» (треугольник Fitts).
- На тач — заменяем hover на press или явную кнопку «еще».
14) Tooltip/меню/дропдауны
Открытие: hover-intent (десктоп) / press (тач), закрытие — по уходу/blur/ESC.
Позиция — к источнику, стрелка выровнена; max-width и переносы включены.
Доступность: `role="tooltip"`, связываем `aria-describedby`; для меню — `role="menu"` + управление стрелками.
15) Специфика iGaming
Коэффициенты/лидерборды: hover подсвечивает строку/ячейку, но не меняет метрики позиционирования (без «прыжков»).
Карточки турниров/бонусов: hover может «оживлять» рамку/иконку, но текстовое CTA и условия остаются читаемыми (≥ 4.5:1).
Ответственные уведомления (18+, лимиты): без эффектов отвлечения; при наведении допускается только подчеркивание ссылок и четкий фокус.
Кнопки ставок/покупок: active-feedback обязателен (визуальный щелчок/вдавливание) и недвусмысленный disable после отправки.
16) Примеры интерфейсных рецептов
Кнопка-CTA (light/dark):css
.cta {
background: var(--role-primary);
color: var(--on-primary);
transition: background-color. 16s var(--ease), transform. 09s var(--ease-acc), box-shadow. 16s var(--ease);
}
@media (hover:hover) and (pointer:fine) {
.cta:hover { background: var(--role-primary-hover); box-shadow: var(--elev-2); }
}
.cta:active { transform: scale(.98); }
.cta:focus-visible { box-shadow: 0 0 0 3px var(--focus-ring); }
Карточка:
css
.card { transition: box-shadow. 16s var(--ease), border-color. 16s var(--ease); }
@media (hover:hover) and (pointer:fine) {
.card:hover { box-shadow: var(--elev-2); border-color: var(--border-strong); }
}
.card:focus-visible { box-shadow: 0 0 0 3px var(--focus-ring); }
Строка таблицы:
css
.table tr { transition: background-color. 12s var(--ease); }
@media (hover:hover) and (pointer:fine) {
.table tr:hover { background: var(--row-hover); }
}
.table tr:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
17) Анти-паттерны
Скрывать критичные действия/меню только за hover.
Изменять размеры/раскладки при наведении (скачки layout).
Опора только на цвет для различимости состояний.
Мерцание, бесконечные пульсации, «кислотные» glow на текстах.
Отсутствие focus-стилей или их невидимость на темной теме.
Наводить курсор `pointer` на неинтерактивные элементы.
18) QA-чек-лист
Доступность
- Все интерактивы достижимы по клавиатуре; фокус видим.
- Hover-контент доступен по `focus`/`aria`.
- Контраст текста и иконок соответствует WCAG.
Поведение
- Hover/active/disabled/visited различимы формой и тоном.
- Нет задержки отклика > 120 мс.
- На тач есть альтернатива hover.
Перформанс
- Анимируются только `transform`/`opacity`.
- Нет тяжелых blur/теней на множестве элементов.
- На длинных списках эффекты сведены к минимуму.
19) Документация в дизайн-системе
Таблица состояний для базовых компонентов (кнопки, ссылки, карточки, поля, строки таблиц).
Токены длительностей/кривых/теней и пример кода для light/dark.
Раздел «Hover vs Touch»: правила альтернатив и примеры.
«Do/Don’t» с короткими клипами и показателями контраста.
Краткое резюме
Эффекты наведения — это вспомогательная, но критичная часть языка интерфейса. Делайте их краткими и предсказуемыми, поддерживайте клавиатуру и тач, обеспечивайте контраст и видимый фокус, анимируйте только дешевые свойства. Тогда интерактивность усиливает ясность и скорость действий, а не мешает им.