Изменение активного пункта меню при прокрутке: JavaScript
Быстрый ответ
Выделять активный пункт меню можно с помощью обработчика события прокрутки (scroll
) в JavaScript. Когда пользователь пролистывает страницу, скрипт определяет текущий активный раздел и обновляет класс active
для соответствующего пункта меню.
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.
Повышаем производительность: Throttling и Debouncing
Слишком частые срабатывания событий прокрутки могут ухудшить производительность. Чтобы избежать этого, можно использовать такие методы, как Throttling и Debouncing.
Метод Throttling ограничивает частоту вызова обработчика событий, что помогает избежать проблем с производительностью.
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 откладывает выполнение функции до тех пор, пока не пройдёт определённый промежуток времени после последнего вызова.
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:
html {
scroll-behavior: smooth;
}
Если же вам необходимо больше контроля над процессом прокрутки, примените JavaScript:
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 для оформления активных пунктов меню на разных устройствах.
@media screen and (max-width: 600px) {
/* Изменения для мобильных версий */
}
Для обеспечения совместимости в разных браузерах, проверяйте поддержку событий прокрутки и других использованных ваших скриптами функций для каждой версии браузера. При необходимости используйте полифиллы для поддержки старых версий браузеров.
Видимым быть: визуальные подсказки и эффективная навигация
Меню должно быть легко восприниматься пользователем. Используйте визуальные акценты (цвета, жирность шрифта, иконки), чтобы подчеркнуть текущий активный раздел.
.menu-item.active {
color: #fff;
background-color: #333;
font-weight: bold;
}
Для более удобной навигации, зафиксируйте меню на странице:
.menu {
position: fixed;
top: 0;
width: 100%;
}
Визуализация
Концепцию работы меню можно представить как систему контрольных точек или станций метро:
🚂 == 🚏 (Главная) === 🚏 (О нас) === 🚏 (Услуги) === 🚏 (Контакты)
В процессе прокрутки страницы, активный пункт меню перемещается, как поезд, останавливающийся на разных станциях:
На Главной: 🚂💡== 🚏 === 🚏 === 🚏
При прокрутке: 🚏 == 🚂💡== 🚏 === 🚏
В разделе Услуги: 🚏 == 🚏 === 🚂💡== 🚏
Таким образом, активный раздел меняется в зависимости от позиции прокрутки.
Адаптируемся к изменениям: обрабатываем динамический контент и ОПП
Динамические элементы, например новый контент или одностраничные приложения (SPA), требуют специального подхода:
// Использование 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() {
// Обновляем активное состояние элементов меню
}
При использовании якорных ссылок необходимо учитывать высоту шапки сайта, чтобы заголовки разделов не затенялись ею:
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);
});
});
Полезные материалы
- Документация по jQuery API: событие scroll — подробнее о прокрутке в jQuery.
- Scrollspy · Bootstrap v4.6 — инструменты Bootstrap для отслеживания прокрутки страницы.
- API Наблюдатель за пересечениями – Веб API | MDN — отслеживание видимости элементов на странице.
- Регулирование частоты обработчиков событий прокрутки для повышения производительности — оптимизация обработки событий прокрутки.
- Липкое содержание в таблице с активным состоянием прокрутки | CSS-Tricks — руководство по созданию подсказывающей навигации.