назад

Универсальный фокус для интерактивных элементов

Описание паттерна

Этот паттерн помогает создать функциональное состояние фокуса для всех интерактивных элементов. Он делает интерфейс доступнее и понятнее для пользователей, которые работают с сайтом с клавиатуры или с помощью вспомогательных технологий.

Код паттерна

  *:focus-visible {
    outline: 3px solid light-dark(#000000, #ffffff);
    outline-offset: 0.25rem;
    border-radius: 0.13rem;
  }

  :root {
    color-scheme: light dark;
  }
Универсальный фокус для интерактивных элементов

Постановка задачи

Нужно обеспечить:

Антипаттерн

Обычно разработчики делали так:

*:focus {
  outline: none; /* убираем фокус */
}

или использовали только чёрный/синий цвет по умолчанию. Это ухудшает доступность особенно, когда в проекте есть переключение между тёмной и светлой темами.

Никогда не отключайте outline для интерактивных элементов. Это нарушает доступность. Либо подготовьте достойную кастомную обводку.

Современный подход

Мы используем селектор :focus-visible и современный цветовой синтаксис light-dark():

*:focus-visible {
  outline: 3px solid light-dark(#000000, #ffffff);
  outline-offset: 0.25rem;
  border-radius: 0.13rem;
}

:root {
  color-scheme: light dark;
}

Почему так лучше?

  1. :focus-visible Срабатывает только при управлении с клавиатуры и вспомогательными технологиями. При клике мышью лишних обводок нет.
  2. light-dark() Позволяет автоматически менять цвет в зависимости от темы: чёрный(#000000) в светлой, белый(#ffffff) в тёмной.
  3. outline-offset и border-radius Делаем обводку чуть смещённой и закруглённой для лучшей визуальной читаемости.
  4. color-scheme: light dark Сообщаем браузеру, что сайт поддерживает обе темы.

Примеры использования

Пример №1: Базовый

<button>Нажми меня</button>
<a href="#">Ссылка</a>
<input type="text" placeholder="Фокус сюда" />

Ссылка

На клавиатуре все элементы получат одинаковый аккуратный фокус. Нажимай Tab, чтобы посмотреть на фокус.

Пример №2: С кастомным цветом

Можно использовать currentcolor, если хочется, чтобы обводка наследовала цвет текста элемента:

*:focus-visible {
  outline: 3px solid currentcolor;
  outline-offset: 0.25rem;
  border-radius: 0.13rem;
}

Обратите внимание

На данный момент самый универсальным и рабочим способом является подход, когда outline вообще не изменяется, то есть оставляется по умолчанию, который принят в конкретном браузере.

Браузер учитывает контрастность цвета обводки и фона. Он прекрасно работает в любой теме, а также если в теме используется противоположный цвет фона у блока, например в тёмной теме может быть блок с светлым фоном. Такой подход работает с любой версией браузера.

Поддержка браузерами

Обсудить паттерн

Этот паттерн можно обсудить на GitHub — задавайте вопросы, делитесь идеями и опытом.

Если у вас есть мысль для нового паттерна, пример из практики или предложение по улучшению — расскажите об этом в обсуждении: любой вклад помогает развивать проект.