Изменение активного пункта меню при прокрутке: JavaScript

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Выделять активный пункт меню можно с помощью обработчика события прокрутки (scroll) в JavaScript. Когда пользователь пролистывает страницу, скрипт определяет текущий активный раздел и обновляет класс active для соответствующего пункта меню.

JS
Скопировать код
window.addEventListener('scroll', () => {
  document.querySelectorAll('section').forEach((sec) => {
    let menuLink = document.querySelector(`.menu-item[href="#${sec.id}"]`);
    if (window.scrollY >= sec.offsetTop && window.scrollY < sec.offsetTop + sec.offsetHeight) {
      menuLink.classList.add('active');
    } else {
      menuLink.classList.remove('active');
    }
  });
});

У каждого раздела вашей страницы должен быть свой идентификатор (ID), а в ссылках меню должен быть атрибут href со ссылкой на нужный идентификатор раздела. Для определения внешнего вида активного класса, воспользуйтесь CSS.

Кинга Идем в IT: пошаговый план для смены профессии

Повышаем производительность: Throttling и Debouncing

Слишком частые срабатывания событий прокрутки могут ухудшить производительность. Чтобы избежать этого, можно использовать такие методы, как Throttling и Debouncing.

Метод Throttling ограничивает частоту вызова обработчика событий, что помогает избежать проблем с производительностью.

JS
Скопировать код
let last_known_scroll_position = 0;
let ticking = false;

let doSomething = (scroll_pos) => {
  // Отслеживаем текущую позицию прокрутки
};

window.addEventListener('scroll', function(e) {
  last_known_scroll_position = window.scrollY;
  if (!ticking) {
    window.requestAnimationFrame(function() {
      doSomething(last_known_scroll_position);
      ticking = false;
    });
    ticking = true;
  }
});

Метод Debounce откладывает выполнение функции до тех пор, пока не пройдёт определённый промежуток времени после последнего вызова.

JS
Скопировать код
function debounce(func, wait) {
  let timeout;

  return function executedFunction() {
    let later = function() {
      clearTimeout(timeout);
      func();
    };

    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
};
window.addEventListener('scroll', debounce(function() {
  // Обрабатываем прокрутку
}, 100));

Просто и плавно: делаем скроллинг нежным

Для плавной прокрутки страницы используйте свойство CSS:

CSS
Скопировать код
html {
  scroll-behavior: smooth;
}

Если же вам необходимо больше контроля над процессом прокрутки, примените JavaScript:

JS
Скопировать код
document.querySelectorAll('.menu-item').forEach(anchor => {
  anchor.addEventListener('click', function(e) {
    e.preventDefault();
    let destination = document.querySelector(this.getAttribute('href'));
    destination.scrollIntoView({ behavior: 'smooth' });
  });
});

Берём на себя обязательства: обеспечиваем адаптивность и кроссбраузерность

Адаптивность меню обеспечивает удобство взаимодействия с сайтом. Используйте медиа-запросы CSS для оформления активных пунктов меню на разных устройствах.

CSS
Скопировать код
@media screen and (max-width: 600px) {
  /* Изменения для мобильных версий */
}

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

Видимым быть: визуальные подсказки и эффективная навигация

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

CSS
Скопировать код
.menu-item.active {
  color: #fff;
  background-color: #333;
  font-weight: bold;
}

Для более удобной навигации, зафиксируйте меню на странице:

CSS
Скопировать код
.menu {
  position: fixed;
  top: 0;
  width: 100%;
}

Визуализация

Концепцию работы меню можно представить как систему контрольных точек или станций метро:

Markdown
Скопировать код
🚂 == 🚏 (Главная) === 🚏 (О нас) === 🚏 (Услуги) === 🚏 (Контакты)

В процессе прокрутки страницы, активный пункт меню перемещается, как поезд, останавливающийся на разных станциях:

Markdown
Скопировать код
На Главной:      🚂💡== 🚏 === 🚏 === 🚏
При прокрутке:   🚏 == 🚂💡== 🚏 === 🚏
В разделе Услуги: 🚏 == 🚏 === 🚂💡== 🚏

Таким образом, активный раздел меняется в зависимости от позиции прокрутки.

Адаптируемся к изменениям: обрабатываем динамический контент и ОПП

Динамические элементы, например новый контент или одностраничные приложения (SPA), требуют специального подхода:

JS
Скопировать код
// Использование MutationObserver для отслеживания изменений в дом-структуре
const observer = new MutationObserver(mutations => {
  mutations.forEach(mutation => {
    if (mutation.addedNodes.length || mutation.removedNodes.length) {
      // Нужно обновить состояние активного пункта меню
    }
  });
});

observer.observe(document.body, { childList: true, subtree: true });

// Отслеживание изменений пути в SPA
window.onhashchange = function() {
  // Обновляем активное состояние элементов меню
}

При использовании якорных ссылок необходимо учитывать высоту шапки сайта, чтобы заголовки разделов не затенялись ею:

JS
Скопировать код
let headerHeight = document.querySelector('.header').offsetHeight;

document.querySelectorAll('.menu-item').forEach(anchor => {
  anchor.addEventListener('click', function(e) {
    let destinationID = this.getAttribute('href').substring(1);
    let destination = document.getElementById(destinationID);
    window.scrollTo(0, destination.offsetTop – headerHeight);
  });
});

Полезные материалы

  1. Документация по jQuery API: событие scroll — подробнее о прокрутке в jQuery.
  2. Scrollspy · Bootstrap v4.6 — инструменты Bootstrap для отслеживания прокрутки страницы.
  3. API Наблюдатель за пересечениями – Веб API | MDN — отслеживание видимости элементов на странице.
  4. Регулирование частоты обработчиков событий прокрутки для повышения производительности — оптимизация обработки событий прокрутки.
  5. Липкое содержание в таблице с активным состоянием прокрутки | CSS-Tricks — руководство по созданию подсказывающей навигации.