Коротко напишу про, напевно, найпопулярнішу і, водночас, найприкрішу помилку верстальників — як наївних початківців, так і безвідповідальних професіоналів. Якщо ви вже здогадались, про що піде мова, стикались з цією проблемою і чесно намагались вирішити, перший розділ можна пропустити.

The problem

Стандартна ситуація: сторінку зверстано, всі відступи/шрифти строго по макету, навіть є адекватні ховери на інтерактивних елементах. Дизайнер, проджект менеджер і замовник задоволені всім, окрім одного: при кліку на інпут або кнопку навколо елемента з’являється некрасива рамка, яка геть не узгоджується з рештою дизайну.

Ставлять задачу: прибрати рамку. Тут абсолютна більшість верстальників-початківців, трохи погугливши, знаходить просте і елегантне рішення:

*:focus {
  outline: none;
}

Рамка зникає, клієнт задоволений, таск закривається і фронтендер переходить до наступної задачі. Більше того, ці три рядки коду тепер слідують за верстальником з проекту в проект.

Єдине “але”: тепер сайтом абсолютно неможливо користуватись без мишки. Outline, який виділяв елемент у фокусі при навігації з клавіатури, тепер невидимий. Юзер може лише здогадуватись, в якому місці сторінки він знаходиться.

(Gif of a confused man blinking)

Цьому сценарію вже стільки років, що, здавалось би, пора вже перестати наступати на одні й ті самі граблі. В тих рідкісних випадках, де проблему доступності сайту все ж визнають, активний стан елемента намагаються показати в інший спосіб — наприклад, через зміну кольору чи прозорості елемента так само, як при наведенні на нього мишкою. Цей спосіб не завжди дієвий, бо напряму залежить від ефективності дизайну конкретного макету. Мені доводилось бачити ховери, які ледь змінюють значення параметра opacity — досить ефективно, коли юзер бачить елемент, над яким тримає курсор, і зовсім не ефективно у випадку навігації клавішею Tab. В таких випадках варто було б інвестувати в додатковий код, який займається специфічно станом :focus. Скажу чесно — мені поки не доводилось бачити, щоб хтось цим займався.

Але є простіший варіант.

The solution

Вдалим компромісом було б зробити так, щоб відвідувачі сайту, які користуються мишкою, не бачили outline взагалі, але щоб power-юзери і люди з обмеженими фізичними можливостями бачили його при навігації з клавіатури. Такий підхід був би універсальним, оскільки не залежав би від імплементації фокус-станів на конкретному сайті.

Саме в такий спосіб працює бібліотека smart-outline. Все, що потрібно — додати її до списку production-залежностей і ініціалізувати після завантаження сторінки.

На прикладі npm:

$ npm install smart-outline
/* index.js */
import smartOutline from 'smart-outline'

smartOutline.init()

Якщо десь в файлах стилів залишився :focus {outline:none;}, прибираємо.

Тепер все працює майже так, як треба. Лишається невеликий баг: якщо перший клік після завантаження сторінки попадає на інтерактивний елемент, рамка з’являється на долю секунди перед тим, як зникнути. Вирішується досить банально:

/* index.js */
import smartOutline from 'smart-outline'

smartOutline.init()
/* імітуємо клік одразу після ініціалізації плагіна, щоб outline зник */
document.querySelector('body').click()

Більше джерел на цю тему можна знайти тут.