Перейти к содержанию
Инструкция

Отключить переходы по пунктам меню на мобильных

Как на мобильных сделать так, чтобы клик по родительскому пункту меню раскрывал подменю, а не уводил на страницу раздела. Современное решение на чистом JS, matchMedia и с сохранением доступности.

Обновлено 22 июля 5 минут чтения

Типичная проблема адаптивного меню: на десктопе подменю раскрывается по наведению, а на телефоне наведения нет. В итоге тап по родительскому пункту сразу уводит на страницу раздела, и до вложенных ссылок пользователь не добирается. Задача – на мобильных перехватить первый тап по пункту с подменю, чтобы он раскрывал список, а не выполнял переход.

Почему старое решение на jQuery устарело

Раньше это делали через $(document).delegate('a', 'click', ...) и проверку видимости бургер-кнопки. Приём рабочий, но у него три слабых места: зависимость от jQuery, определение «мобильности» по видимости элемента вместо реального размера экрана и полное отсутствие доступности – скринридер не понимает, что пункт стал кнопкой-раскрывашкой. Сегодня всё это решается на чистом JavaScript.

Определяем мобильный режим правильно

Вместо проверки :visible используйте window.matchMedia() – он опрашивает ту же контрольную точку, что и CSS, и не зависит от вёрстки:

const mobile = window.matchMedia("(max-width: 992px)");

Перехватываем клик на чистом JS

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

const menu = document.querySelector("#main-menu");

menu.addEventListener("click", (e) => {
    const link = e.target.closest("a.has-submenu");
    if (!link) return;

    if (mobile.matches) {
        e.preventDefault();               // отменяем переход
        const item = link.parentElement;
        const expanded = item.classList.toggle("is-open");
        link.setAttribute("aria-expanded", expanded);
    }
});

Обратите внимание: отмену перехода получают только пункты с классом has-submenu. Обычные ссылки без вложенного меню продолжают работать как ссылки – это важно, иначе на мобильных перестанет работать вся навигация.

Доступность: не ломайте семантику

Если пункт на мобильных перестаёт быть ссылкой и становится переключателем, об этом нужно сообщить вспомогательным технологиям:

  • Добавляйте aria-expanded="false" на пункты с подменю и переключайте значение при раскрытии (в коде выше это уже сделано).
  • Оборачивайте меню в <nav aria-label="Основное меню">.
  • Убедитесь, что подменю раскрывается и с клавиатуры: событие click срабатывает и по Enter на ссылке, так что базовый кейс закрыт, но проверьте порядок фокуса.
  • Не прячьте у родителя реальную ссылку насовсем – оставьте пользователю способ попасть на страницу раздела (например, отдельной ссылкой «Перейти в раздел» внутри раскрытого подменю).

Частые ошибки

  • Отключили переход у всех ссылок. Тогда на телефоне не работает вообще ничего. Отменяйте переход только у пунктов с подменю.
  • Определяете мобильность по ширине окна в JS-переменной один раз. При повороте экрана значение устаревает. matchMedia всегда актуален через .matches.
  • Нет визуального признака раскрытия. Пользователь не понимает, что пункт раскрылся. Показывайте стрелку/шеврон и меняйте её по классу is-open.

Тему меню продолжают заметки как вручную добавить подпункт в подменю Битрикса и вывод блоков только на определённых страницах. Если правите ещё и мобильные кнопки, посмотрите как заменить текст кнопки поиска на иконку.

Частые вопросы

Почему нельзя просто отменить переход у всех ссылок меню?

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

Чем matchMedia лучше проверки видимости бургер-кнопки?

matchMedia опрашивает ту же брейкпоинт-логику, что и CSS, не зависит от вёрстки и всегда актуален через свойство .matches, в том числе после поворота экрана.

Нужен ли jQuery для этого решения?

Нет. Современный делегированный обработчик на addEventListener с event.target.closest полностью заменяет старый $(document).delegate.

Как не потерять доступность при отключении переходов?

Переключайте атрибут aria-expanded на пункте, оборачивайте меню в nav с aria-label и оставьте пользователю отдельную ссылку на страницу раздела внутри раскрытого подменю.

Как пользователю всё-таки попасть на страницу раздела?

Добавьте в раскрытое подменю отдельную ссылку вида «Перейти в раздел» – так родительский пункт раскрывает список, а переход остаётся доступным.

Валентина Меланина

Хотите обсудить свой проект?

Помогу с разработкой, аналитикой и AI-видимостью вашего сайта

Если у вас есть задача — от внедрения разметки и аналитики до полной переработки сайта — напишите, обсудим объём и подход.