Активные состояния навигации

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

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

<nav>
  <ul>
    <li><a href="#section1" class="nav-link">Раздел 1</a></li>
    <li><a href="#section2" class="nav-link">Раздел 2</a></li>
    <li><a href="#section3" class="nav-link">Раздел 3</a></li>
  </ul>
</nav>

<section id="section1">...</section>
<section id="section2">...</section>
<section id="section3">...</section>

Инициализация Smooth Scroll

Библиотека Smooth Scroll обеспечивает плавный переход при клике на якорные ссылки. Инициализация выполняется следующим образом:

const scroll = new SmoothScroll('a[href*="#"]', {
  speed: 600,
  offset: 0,
  clip: true,
});
  • speed — скорость анимации в миллисекундах.
  • offset — смещение от верхней границы окна (удобно при фиксированной шапке).
  • clip — предотвращает скролл за пределы документа.

Отслеживание позиции секций

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

const sections = document.querySelectorAll('section');
const navLinks = document.querySelectorAll('.nav-link');

function activateNav() {
  let scrollPos = window.scrollY + window.innerHeight / 2;

  sections.forEach((section, index) => {
    if (scrollPos >= section.offsetTop && scrollPos < section.offsetTop + section.offsetHeight) {
      navLinks.forEach(link => link.classList.remove('active'));
      navLinks[index].classList.add('active');
    }
  });
}

window.addEventListener('scroll', activateNav);
  • scrollY — текущая позиция скролла по вертикали.
  • offsetTop — расстояние секции от верхнего края документа.
  • offsetHeight — высота секции.
  • Использование window.innerHeight / 2 позволяет активировать ссылку ближе к центру экрана.

Обработка кликов и синхронизация с Smooth Scroll

Smooth Scroll позволяет отслеживать завершение анимации перехода, чтобы корректно активировать ссылку:

scroll.on('scrollEnd', function (anchor, toggle) {
  navLinks.forEach(link => link.classList.remove('active'));
  if (toggle) toggle.classList.add('active');
});
  • anchor — DOM-элемент, на который произошёл скролл.
  • toggle — ссылка, инициировавшая переход.
  • Это гарантирует синхронизацию активного состояния при быстром клике по меню.

Динамическая адаптация при изменении размера окна

При изменении размеров окна положение секций относительно видимой области меняется. Для корректной работы активных состояний важно пересчитывать координаты:

window.addEventListener('resize', () => {
  sections.forEach(section => {
    section.dataset.top = section.offsetTop;
  });
});
  • Можно сохранять координаты в data-top для оптимизации вычислений при скролле.

Оптимизация производительности

  • Использовать requestAnimationFrame для обработки события scroll, чтобы избежать лагов при высокой частоте событий:
let ticking = false;

window.addEventListener('scroll', () => {
  if (!ticking) {
    window.requestAnimationFrame(() => {
      activateNav();
      ticking = false;
    });
    ticking = true;
  }
});
  • Минимизирует количество вызовов функции при быстром скролле.

Настройка CSS для активной ссылки

Ключевой момент — визуальное выделение текущей ссылки:

.nav-link.active {
  color: #ff6600;
  font-weight: bold;
  border-bottom: 2px solid #ff6600;
}
  • Поддерживаются любые эффекты: цвет, шрифтовое начертание, анимация underline.
  • Можно использовать CSS-переходы для плавного изменения стиля.

Поддержка вложенных меню и длинных страниц

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

Итоговая схема работы

  1. Инициализация Smooth Scroll для плавного перехода.
  2. Отслеживание скролла и вычисление видимой секции.
  3. Присвоение активного класса соответствующей ссылке.
  4. Синхронизация с кликами по меню через события Smooth Scroll.
  5. Адаптация при изменении размеров окна.
  6. Оптимизация через requestAnimationFrame для плавности.

Эта схема обеспечивает точное, визуально корректное отображение активного состояния навигации на странице с плавной прокруткой.