CSS / Адаптивность
Hover-эффекты для кнопок в CSS: состояния без вреда для доступности
Как оформить :hover, :focus-visible и :active у кнопки, добавить плавный переход и учесть сенсорные устройства и reduced motion.
Содержание статьи
Псевдокласс :hover применяется, когда указатель находится над элементом. Эффект помогает показать интерактивность, но не может быть единственным способом получить информацию: на сенсорном экране постоянного hover нет, а клавиатурный пользователь перемещается через фокус.
Начните с настоящей кнопки:
<button class="button" type="button">Открыть настройки</button>.button { min-block-size: 2.75rem; padding: 0.7rem 1.1rem; font: inherit; font-weight: 700; color: #ffffff; background-color: #5b21b6; border: 2px solid #5b21b6; border-radius: 0.6rem; cursor: pointer;}.button:hover { background-color: #4c1d95; border-color: #4c1d95;}<button> уже поддерживает Enter, пробел, фокус и состояние disabled. Кликабельный <div> потребовал бы вручную воспроизводить это поведение.
Плавный переход
transition задают исходному элементу, чтобы анимация работала в обе стороны:
.button { transition: color 160ms ease, background-color 160ms ease, border-color 160ms ease, transform 160ms ease;}.button:hover { transform: translateY(-1px);}Не пишите transition: all: браузер может анимировать неожиданные свойства, включая размеры и положение. Перечисляйте только нужные.
Анимация transform обычно плавнее изменения top или margin, потому что не перестраивает окружающую раскладку.
Клавиатурный фокус
Hover не заменяет видимый фокус:
.button:focus-visible { outline: 3px solid #f59e0b; outline-offset: 3px;}Не отключайте outline, если не добавили равноценный, хорошо заметный индикатор. Псевдокласс :focus-visible обычно показывает контур при клавиатурной навигации и не мешает обычному клику мышью.
Если hover-оформление отражает важное состояние, примените его и при фокусе:
.button:hover,.button:focus-visible { background-color: #4c1d95; border-color: #4c1d95;}Состояние нажатия
:active действует во время активации:
.button:active { transform: translateY(0); background-color: #3b176f;}Не путайте его с постоянным выбранным состоянием. Для переключателя состояние хранится в HTML, например aria-pressed="true", и стилизуется по атрибуту.
<button class="toggle" type="button" aria-pressed="false">Показывать сетку</button>.toggle[aria-pressed="true"] { color: #ffffff; background-color: #344054;}JavaScript должен менять aria-pressed вместе с фактическим состоянием.
Disabled-состояние
<button class="button" type="submit" disabled>Сохранение…</button>.button:disabled { cursor: not-allowed; opacity: 0.55; transform: none;}Нативная disabled-кнопка не получает фокус и не отправляет форму. Не используйте это состояние для объяснения ошибки без соседнего текста: пользователь должен понимать, что нужно исправить.
Устройства без hover
Сложный эффект можно ограничить устройствами, которые действительно поддерживают наведение:
@media (hover: hover) and (pointer: fine) { .button:hover { transform: translateY(-2px); box-shadow: 0 0.6rem 1.5rem rgb(52 64 84 / 20%); }}Базовый цветовой отклик можно оставить для всех, но функциональность не должна зависеть от наведения.
Уменьшение движения
Учитывайте системную настройку:
@media (prefers-reduced-motion: reduce) { .button { transition-duration: 0.01ms; } .button:hover, .button:active { transform: none; }}Для простой смены цвета полное отключение не всегда обязательно, но заметные перемещения и масштабирование лучше убрать.
Кнопка или ссылка
Кнопка запускает действие на текущей странице: открывает меню, отправляет форму, меняет настройку. Ссылка ведёт по адресу. Оформлять ссылку как кнопку можно, но семантика остаётся ссылочной:
<a class="button" href="/courses/html">Перейти к курсу</a>Не добавляйте href="#" для действия и не используйте кнопку для обычного перехода.
Частые ошибки
- hover меняет размер рамки и сдвигает соседние элементы;
- текст и фон в одном из состояний теряют контраст;
outline: noneоставляет клавиатурного пользователя без ориентира;transition: allанимирует лишние свойства;- эффект доступен только мыши;
- кнопка масштабируется настолько, что перекрывает соседний интерфейс;
- важная подсказка появляется только при наведении.
Что запомнить
:hover — лишь одно из состояний интерактивного элемента. Проектируйте вместе hover, focus-visible, active и disabled, не меняйте размеры макета и учитывайте сенсорные устройства и prefers-reduced-motion. Поведение должно оставаться понятным без анимации и наведения.