Клавиатурная навигация

Клавиатурная навигация — важный аспект доступности интерфейса, который напрямую влияет на восприятие анимаций при прокрутке. При использовании библиотеки AOS (Animate On Scroll) необходимо учитывать, что пользователь может перемещаться по странице не только с помощью мыши или сенсорного экрана, но и через клавиатуру — с использованием клавиш Tab, Shift + Tab, Enter, Space, стрелок и других.

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


Поведение AOS при навигации через Tab

По умолчанию AOS отслеживает положение элементов относительно viewport и запускает анимации при их появлении в зоне видимости. При перемещении по странице с помощью Tab:

  • браузер прокручивает страницу автоматически, но не всегда инициирует события scroll так, как ожидает AOS
  • элемент может получить фокус, но остаться в состоянии без анимации (opacity: 0, transform и т.д.)
  • пользователь видит «невидимый» или частично скрытый элемент

Атрибут tabindex и его влияние

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

  • интерактивные элементы (<a>, <button>, <input>) фокусируются автоматически
  • для других элементов требуется tabindex="0" или выше

Пример:

<div data-aos="fade-up" tabindex="0">
  Контент с анимацией
</div>

Добавление tabindex делает элемент доступным для навигации, но не решает проблему запуска анимации.


Принудительный запуск анимации при фокусе

Для корректной работы с клавиатурой необходимо отслеживать событие focus и вручную инициировать анимацию.

Пример решения:

document.querySelectorAll('[data-aos]').forEach(el => {
  el.addEventListener('focus', () => {
    el.classList.add('aos-animate');
  });
});

Особенности:

  • класс aos-animate — ключевой триггер для отображения анимации
  • добавление класса вручную позволяет обойти зависимость от scroll

Синхронизация с внутренним состоянием AOS

AOS управляет состоянием элементов через собственный механизм, включая:

  • массив отслеживаемых элементов
  • флаги видимости
  • события обновления (refresh, refreshHard)

Прямое вмешательство (например, добавление класса) может нарушить согласованность. Более корректный подход:

document.querySelectorAll('[data-aos]').forEach(el => {
  el.addEventListener('focus', () => {
    AOS.refresh();
  });
});

Однако это не всегда гарантирует мгновенное появление анимации.


Использование IntersectionObserver как альтернативы

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

Пример:

const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.classList.add('aos-animate');
    }
  });
});

document.querySelectorAll('[data-aos]').forEach(el => {
  observer.observe(el);
});

Это решение:

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

Управление фокусом при анимациях

Анимации могут мешать восприятию, если элемент получает фокус до завершения появления:

  • элемент может быть смещён (transform)
  • opacity может быть равен 0
  • пользователь не понимает, где находится фокус

Рекомендуется:

  • избегать длительных анимаций для фокусируемых элементов
  • использовать data-aos-duration с умеренными значениями (300–600 мс)
  • отключать transform для интерактивных компонентов

Пример:

<button data-aos="fade" data-aos-duration="400">
  Кнопка
</button>

Обработка focus-visible

Современные браузеры поддерживают псевдокласс :focus-visible, который позволяет отделить клавиатурный фокус от мышиного.

Пример:

:focus-visible {
  outline: 2px solid #000;
}

При использовании AOS важно, чтобы:

  • outline не скрывался из-за overflow или transform
  • анимации не мешали отображению фокуса

Избежание скрытого контента

AOS по умолчанию скрывает элементы до анимации:

[data-aos] {
  opacity: 0;
}

Это создаёт проблему доступности:

  • элементы существуют в DOM
  • доступны для фокуса
  • но визуально невидимы

Решения:

  1. Использовать data-aos-once="true" — элемент анимируется один раз и остаётся видимым
  2. Переопределить стили:
[data-aos] {
  opacity: 1;
  transform: none;
}
[data-aos].aos-animate {
  opacity: 1;
}
  1. Отключать AOS для важных интерактивных блоков

Управление порядком табуляции

Неправильный порядок tabindex может приводить к:

  • перескакиванию через элементы
  • фокусировке невидимых блоков
  • нарушению логики интерфейса

Рекомендуется:

  • избегать tabindex > 0
  • использовать естественный порядок DOM
  • группировать анимируемые элементы логически

Интеграция с ARIA

Для улучшения доступности можно использовать ARIA-атрибуты:

<div data-aos="fade-up" aria-hidden="true">
  Контент
</div>

После анимации:

el.addEventListener('focus', () => {
  el.classList.add('aos-animate');
  el.setAttribute('aria-hidden', 'false');
});

Это позволяет:

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

Отключение анимаций для клавиатурных пользователей

В некоторых случаях предпочтительно полностью отключать AOS при навигации с клавиатуры.

Пример:

let isKeyboardUser = false;

document.addEventListener('keydown', () => {
  isKeyboardUser = true;
});

if (isKeyboardUser) {
  AOS.init({
    disable: true
  });
}

Альтернативный подход — использовать медиа-запрос:

AOS.init({
  disable: window.matchMedia('(prefers-reduced-motion: reduce)').matches
});

Практические рекомендации

  • не применять сложные анимации к элементам формы
  • избегать задержек (data-aos-delay) для интерактивных компонентов
  • проверять навигацию только клавиатурой на всех этапах разработки
  • тестировать с отключённым JavaScript
  • учитывать поведение скринридеров

Типовые ошибки

1. Фокус на невидимом элементе Причина: opacity: 0 до анимации Решение: принудительное отображение при focus

2. Анимация не запускается Причина: отсутствие scroll-события Решение: ручное добавление aos-animate

3. Нарушение логики навигации Причина: неправильный tabindex Решение: соблюдение естественного порядка DOM

4. Потеря фокуса Причина: transform или overflow Решение: минимизация визуальных эффектов для фокусируемых элементов


Совмещение UX и анимаций

Грамотное использование AOS в сочетании с клавиатурной навигацией требует баланса:

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

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