Smooth Scroll в JavaScript позволяет не только анимированно прокручивать страницу к определённым элементам, но и управлять фокусом на этих элементах, что особенно важно для доступности (accessibility) и интерактивных интерфейсов. Работа с фокусом гарантирует, что пользователь после прокрутки попадёт непосредственно на нужный элемент, а клавиатурная навигация останется логичной.
После завершения анимации прокрутки можно программно установить фокус
на элемент с помощью метода focus(). Например:
const target = document.querySelector('#section2');
target.scrollIntoView({ beh * avior: 'smooth' });
target.focus({ preventScroll: true });
Ключевой момент: использование опции
preventScroll: true предотвращает повторную прокрутку при
установке фокуса. Без неё браузер может мгновенно подскроллить страницу,
нарушив плавность анимации.
Для элементов, которые по умолчанию не могут получать фокус
(например, <div> или <span>),
необходимо явно добавить атрибут tabindex. Наиболее
безопасный подход:
<div id="section2" tabindex="-1">Контент секции 2</div>
tabindex="-1" делает элемент доступным для фокуса через
JavaScript, но не добавляет его в последовательность клавиатурной
навигации. Это идеальный вариант для целей Smooth Scroll.
Если используется сторонняя библиотека Smooth Scroll, например, cferdinandi/smooth-scroll, фокус можно устанавливать в колбэке после завершения анимации. Пример:
const scroll = new SmoothScroll('a[href*="#"]', {
speed: 500,
offset: 20,
clip: true
});
document.querySelectorAll('a[href*="#"]').forEach(link => {
link.addEventListener('click', function(event) {
const target = document.querySelector(this.getAttribute('href'));
scroll.animateScroll(target, this, {
after: () => {
target.setAttribute('tabindex', '-1');
target.focus({ preventScroll: true });
}
});
});
});
Важно: атрибут tabindex устанавливается
непосредственно перед фокусом. После завершения анимации его можно
оставить или удалять, если нужно сохранить чистоту DOM.
Для элементов, которые создаются динамически (например, через AJAX или React), порядок действий следующий:
tabindex="-1".focus({ preventScroll: true }).function scrollToDynamicElement(elementId) {
const element = document.getElementById(elementId);
element.setAttribute('tabindex', '-1');
element.scrollIntoView({ beh * avior: 'smooth' });
element.addEventListener('transitionend', () => {
element.focus({ preventScroll: true });
}, { once: true });
}
Использование события transitionend или
scroll позволяет гарантировать, что фокус будет установлен
только после завершения визуальной анимации.
Для элементов, на которые переносится фокус, желательно учитывать ARIA-атрибуты:
aria-labelledby — указывает на заголовок элемента.aria-live="polite" — уведомляет пользователей
скринридеров о появлении нового контента без резкой смены фокуса.role="region" — определяет логическую область для
навигации.Пример:
<div id="section2" tabindex="-1" role="region" aria-labelledby="section2-title">
<h2 id="section2-title">Секция 2</h2>
<p>Контент секции.</p>
</div>
При использовании Smooth Scroll важно сохранить возможность возвращения к предыдущему фокусу, особенно для форм или интерактивных списков. Для этого можно сохранять активный элемент перед прокруткой:
const previousFocus = document.activeElement;
target.scrollIntoView({ beh * avior: 'smooth' });
target.focus({ preventScroll: true });
// при необходимости позже
previousFocus.focus();
Это обеспечивает предсказуемое поведение для пользователей клавиатуры и скринридеров.
offset), чтобы заголовки не прилипали к верхней
границе окна.Управление фокусом в сочетании с плавной прокруткой обеспечивает интуитивное взаимодействие и улучшает доступность интерфейса, что критично для современных веб-приложений.