Не ставить фокус по клику
Проблема заключалась в следующем: когда имеется интерактивный элемент с :focus
стилем и вы щелкаете по этому элементу, на нём остаётся focus стиль (outline
обводка). У нативной кнопки всё работает as expected, но стоит её добавить любой стиль и, как побочный эффект, меняется её поведение.
<button >Без фокуса после клика</button>
<button style="background-color: lightgray;">Фокус после клика</button>
Конечно outline можно убрать, но с интерактивными элементам так делать не стоит, так как он обеспечивает визуальную обратную связь для элементов, которые имеют «фокус» при навигации по документу с помощью клавиши TAB (или эквивалентной). Это особенно полезно для людей, которые не могут использовать мышь или имеют нарушения зрения. Если вы удалите outline
, вы сделаете свой сайт недоступным для этих людей.
Решение на JS
Отмена действия браузера по-умолчанию. Есть два способа отменить действие браузера. Основной способ – это воспользоваться объектом event
. Для отмены действия браузера существует стандартный метод event.preventDefault(). Если же обработчик назначен через on<событие> (не через addEventListener), то также можно вернуть false
из обработчика.
В следующем примере при клике по ссылке переход не произойдёт:
<a href="/" onclick="return false">Нажми здесь</a>
или
<a href="/" onclick="event.preventDefault()">здесь</a>
Нажми здесь или здесь
Для события mousedown на кнопке действием браузера по-умолчанию является установка фокуса. Если отменить событие mousedown
, то фокусирования не произойдёт.
Результат
document
.querySelector('#custom')
.addEventListener('mousedown', e => e.preventDefault());
Возможность установить фокус через Tab
сохранена.
Еще одно решение на JS
Если есть причина не отменять действие браузера по-умолчанию, то можно сделать ручное управление фокусом. Идея следующая:
const isMouseDown = false; // в примере будет работать только для 1ой кнопки
const button = document.querySelector('button');
button.addEventListener('mousedown', () => (isMouseDown = true));
button.addEventListener('mouseup', () => (isMouseDown = false));
button.addEventListener('focus', () => {
if (isMouseDown) {
button.blur();
}
};
Как там у других
- United States Web Design System - фокус остаётся
- United Kindom Design System - фокус остаётся
- Microsoft Design System - фокус НЕ остаётся
- Carbon Design System - фокус остаётся
- SalesForce Design System - фокус остаётся
- Контур - фокус НЕ остаётся
- Альфа - фокус НЕ остаётся
Нативное поведение повторяют не все, даже государственные дизайн-системы. Мне кажется это не есть гуд.