:hover и :active — CSS-псевдоклассы. Первый описывает наведение, второй — момент активации элемента. На сенсорном экране браузер может имитировать наведение, поэтому эффект после касания иногда «залипает».
Наведение — только при поддержке hover
Медиазапрос (hover: hover) проверяет, умеет ли основное устройство ввода удобно наводить указатель. Это не проверка «компьютер или телефон»: у устройства могут быть и сенсорный экран, и мышь.
@media (hover: hover) {
.btn:hover {
background-color: #dbeafe;
}
}
.btn:active {
transform: scale(0.97);
}
.btn:focus-visible {
outline: 2px solid #1d4ed8;
outline-offset: 3px;
}
Добавь эти правила после базовых стилей кнопки. :active оставлен вне медиазапроса, чтобы не исключать сенсорный ввод. Для действий используй настоящий <button type="button">: он поддерживает клавиатуру и фокус. Отдельный JavaScript для обычного эффекта нажатия обычно не нужен.
Когда всё-таки нужен JavaScript
Если интерфейсу нужен собственный класс на время нажатия указателем, используй Pointer Events: они охватывают мышь, перо и касание. Обрабатывай отпускание, отмену и потерю захвата указателя.
document.querySelectorAll('.btn').forEach((button) => {
const reset = () => button.classList.remove('is-pressed');
button.addEventListener('pointerdown', (event) => {
if (!event.isPrimary || event.button !== 0 || button.disabled) return;
button.setPointerCapture(event.pointerId);
button.classList.add('is-pressed');
});
button.addEventListener('pointerup', reset);
button.addEventListener('pointercancel', reset);
button.addEventListener('lostpointercapture', reset);
button.addEventListener('blur', reset);
});
.btn.is-pressed {
transform: scale(0.97);
}
Подключи скрипт с defer или поставь его после кнопок. Если кнопок нет, пример ничего не делает. Он добавляет только визуальное состояние указателя: действие кнопки оставь на click, а CSS :active и :focus-visible сохрани для клавиатуры. Проверь касание, прокрутку пальцем, мышь и клавиши Tab, Enter, Space.