ally.style.focusSource

Модуль ally.style.focusSource входит в набор инструментов библиотеки ally.js и предназначен для визуального отображения источника получения фокуса элементом интерфейса. В современных веб-приложениях элементы могут получать фокус различными способами: с помощью клавиатуры, мыши, сенсорного ввода, программного управления через JavaScript. Поведение интерфейса и визуальные стили нередко должны отличаться в зависимости от того, каким способом был установлен фокус.

Например:

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

Модуль позволяет автоматически отслеживать источник фокуса и добавлять соответствующие CSS-классы к корневому элементу документа. Эти классы затем используются для управления стилями интерфейса.


Проблема определения источника фокуса

Стандартная модель DOM не предоставляет надёжного способа определить, каким способом элемент получил фокус. Событие focus сообщает только факт изменения фокуса, но не содержит информации о его источнике.

На практике фокус может быть установлен следующими способами:

Источник Пример
Клавиатура Tab, Shift+Tab, стрелки
Мышь Клик по элементу
Сенсорный ввод Тап на мобильных устройствах
Программно element.focus()
Скриптовая навигация фокус после закрытия модального окна

Различные браузеры и устройства по-разному обрабатывают эти сценарии. В результате разработчики часто реализуют собственные механизмы отслеживания ввода. Модуль ally.style.focusSource решает эту задачу на уровне библиотеки.


Общий принцип работы

Модуль работает на основе глобального отслеживания событий пользовательского ввода. Он анализирует последовательность событий:

  • keydown
  • mousedown
  • touchstart
  • pointerdown
  • focus

На основании этих событий определяется предполагаемый источник фокуса.

Алгоритм работы можно описать следующим образом:

  1. Отслеживается последнее событие пользовательского ввода.
  2. При возникновении события focus анализируется тип предыдущего взаимодействия.
  3. Определяется источник фокуса.
  4. К элементу document.documentElement добавляется CSS-класс, описывающий источник.

Подключение и инициализация

Модуль активируется через вызов функции ally.style.focusSource().

import ally from 'ally.js';

const handle = ally.style.focusSource();

После выполнения:

  • библиотека начинает отслеживать пользовательский ввод;
  • к корневому элементу документа (<html>) добавляются CSS-классы;
  • возвращается объект-дескриптор, позволяющий отключить функциональность.

Отключение:

handle.disengage();

Генерируемые CSS-классы

Модуль добавляет к элементу <html> классы, отражающие источник фокуса. Наиболее распространённые классы:

Класс Значение
ally-focus-source-keyboard фокус получен через клавиатуру
ally-focus-source-mouse фокус установлен кликом мыши
ally-focus-source-touch фокус получен через сенсорный ввод
ally-focus-source-script фокус установлен программно

Классы автоматически обновляются при каждом изменении источника фокуса.

Пример DOM после взаимодействия клавиатурой:

<html class="ally-focus-source-keyboard">

После клика мышью:

<html class="ally-focus-source-mouse">

Использование классов в CSS

Основная цель модуля — управление стилями в зависимости от способа взаимодействия пользователя.

Отображение рамки только при навигации клавиатурой

html.ally-focus-source-keyboard :focus {
  outline: 2px solid #3b82f6;
}

html.ally-focus-source-mouse :focus {
  outline: none;
}

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


Различные стили для разных источников

html.ally-focus-source-keyboard button:focus {
  box-shadow: 0 0 0 3px rgba(0,0,255,0.4);
}

html.ally-focus-source-touch button:focus {
  box-shadow: 0 0 0 5px rgba(0,0,0,0.2);
}

Таким образом можно адаптировать интерфейс под различные устройства ввода.


Определение программного фокуса

Фокус может устанавливаться через Jav * aScript:

element.focus();

В подобных случаях пользователь не инициировал действие напрямую. Модуль фиксирует этот сценарий и устанавливает класс:

ally-focus-source-script

Это позволяет применять отдельные стили.

Пример:

html.ally-focus-source-script :focus {
  outline: none;
}

В некоторых интерфейсах программный фокус используется для управления модальными окнами, меню и другими интерактивными компонентами.


Поддержка Pointer Events

Современные браузеры используют Pointer Events, объединяющие мышь, стилус и сенсорный ввод. Модуль корректно обрабатывает такие события:

  • pointerdown
  • pointerup

Тип указателя (pointerType) используется для различения источника:

pointerType источник
mouse мышь
touch сенсорный ввод
pen стилус

Это обеспечивает корректную работу на устройствах:

  • планшеты
  • гибридные ноутбуки
  • устройства с активным стилусом

Взаимодействие с системой accessibility

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

Модуль ally.style.focusSource помогает реализовать следующие рекомендации accessibility:

  1. Сохранять визуальный индикатор фокуса при клавиатурной навигации.
  2. Не мешать пользователям мыши лишними рамками.
  3. Обеспечивать предсказуемое поведение интерфейса.

Это соответствует рекомендациям WCAG, согласно которым индикатор фокуса должен быть заметным.


Пример интеграции в интерфейс формы

HTML:

<form>
  <input type="text" placeholder="Имя">
  <input type="email" placeholder="Email">
  <button>Отправить</button>
</form>

Jav * aScript:

import ally from 'ally.js';

ally.style.focusSource();

CSS:

html.ally-focus-source-keyboard input:focus,
html.ally-focus-source-keyboard button:focus {
  outline: 3px solid #2563eb;
}

html.ally-focus-source-mouse input:focus,
html.ally-focus-source-mouse button:focus {
  outline: none;
}

Поведение интерфейса:

  • при использовании Tab появляется чёткая рамка фокуса;
  • при клике мышью рамка скрыта;
  • при программной установке фокуса стиль можно настроить отдельно.

Работа в сложных интерфейсах

Модуль особенно полезен в сложных UI-системах:

  • SPA-приложениях
  • дизайн-системах
  • UI-фреймворках
  • административных панелях
  • интерфейсах с большим количеством интерактивных элементов

Он централизует логику определения источника фокуса и избавляет от необходимости реализовывать подобные механизмы в каждом компоненте.


Управление жизненным циклом

Функция ally.style.focusSource() возвращает объект управления.

Пример:

const focusSource = ally.style.focusSource();

Отключение:

focusSource.disengage();

После отключения:

  • обработчики событий удаляются;
  • CSS-классы больше не обновляются.

Это может быть полезно:

  • при уничтожении SPA-страницы
  • при перезапуске интерфейса
  • при тестировании компонентов

Особенности производительности

Модуль использует минимальное количество обработчиков событий и работает на уровне документа. Основные характеристики:

  • один глобальный набор слушателей событий;
  • отсутствие сложных вычислений;
  • обновление классов только при изменении источника.

Благодаря этому модуль практически не влияет на производительность страницы даже в крупных приложениях.


Отличие от псевдокласса :focus-visible

Современные браузеры поддерживают CSS-псевдокласс:

:focus-visible

Он также предназначен для отображения фокуса только при клавиатурной навигации. Однако модуль ally.style.focusSource имеет ряд преимуществ:

Возможность ally.style.focusSource :focus-visible
поддержка старых браузеров да нет
различие mouse / touch да нет
различие script focus да нет
управление через JS да ограничено

Поэтому модуль остаётся актуальным в проектах, где требуется более точное управление поведением фокуса.


Использование в дизайн-системах

В масштабируемых дизайн-системах классы источника фокуса можно использовать как глобальное состояние интерфейса.

Пример:

html.ally-focus-source-keyboard {
  --focus-ring-size: 3px;
}

html.ally-focus-source-touch {
  --focus-ring-size: 5px;
}

Далее переменные применяются в компонентах:

button:focus {
  outline: var(--focus-ring-size) solid #2563eb;
}

Это делает систему оформления более гибкой и легко масштабируемой.


Роль в архитектуре ally.js

Библиотека ally.js ориентирована на улучшение доступности веб-интерфейсов. В её архитектуре можно выделить несколько категорий модулей:

  • управление фокусом
  • обнаружение фокусируемых элементов
  • стилизация фокуса
  • управление доступностью компонентов

Модуль ally.style.focusSource относится к категории стилизации и визуальной индикации фокуса. Он не изменяет поведение DOM-фокуса напрямую, а предоставляет информацию о контексте взаимодействия пользователя.

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