Доброго времени суток 🙂
Сегодня мы поговорим о довольно тривиальной задаче – выделении активного пункта меню с помощью jQuery.
Для начала, традиционно, пару слов о том, кому будет полезна данная информация.
В первую очередь, сегодняшняя статья будет бесценной для тех, кто решил создать сайт «с нуля» на чистом php+css+html+javascript или с помощью фреймворков.
Бесценна – потому что в этом случае у вас не будет готового функционала, как у любителей CMS, поэтому выделение активного пункта меню придётся реализовывать самостоятельно.
Но, если вы всё-таки относитесь к фанатам создания сайта на CMS, где данный функционал доступен «из коробки», приводимая далее информация не будет такой уж бесполезной, т.к. никто не сможет вам гарантировать, что устанавливаемый графический шаблон будет без багов 🙂
А бывает, что после установки какого-то модуля, ломается уже существующий функционал…
В общем, принципы организации подсветки активного пункта меню будут полезны всем, без исключения.
К тому же, стоит подчеркнуть, что рассматриваемый нами сегодня способ является кроссплатформенным, поэтому он подойдёт он всем без исключения.
Итак, переходим от лирики к практике.
Постановка задачи
Для начала опишем проблему более детально. Т.е. составим постановку задачи, которая является половиной успеха.
Итак, у нас есть главное меню сайта, которое состоит из пунктов, содержащих ссылки на страницы сайта.
Пункты меню, соответственно, имеют названия, созвучные с названиями страниц сайта.
Для примера возьмём главное меню, характерное для сайтов-визиток:
Как видно на картинке, меню в нашем случае состоит из следующих элементов:
- Home – при нажатии открывается главная страница сайта, соответственно, ссылка на элементе будет «/»;
- About – содержит ссылку «about», ведёт на соответствующую страницу;
- Services – ссылка «services»;
- Blog – ссылка «blog»;
- Contacts – ссылка «contacts».
HTML-код нашего меню будет таким:
<div class="menu"> <ul> <li><a href="/">Home</a></li> <li><a href="/about">About</a></li> <li><a href="/services">Services</a></li> <li><a href="/blog">Blog</a></li> <li><a href="/contacts">Contacts</a></li> </ul> </div>
Наша задача будет заключаться в выделении пункта меню, который соответствует текущей странице, т.е. странице, на которой находится пользователь сейчас.
Итак, все исходные данные и то, что должны получить в итоге, мы описали. Переходим к описанию алгоритма и его реализации.
Подсветка активного пункта меню – алгоритм
Итак, как же мы будет выделять текущий элемент? Самый лучший способ – поменять либо цвет его текста, либо фон.
Лично мне больше нравится первый вариант, вы же можете поступить так, как вам нравится.
Для подсветки текущего пункта меню добавим класс, который будет делать текст ссылки, содержащейся в нём, синим:
.current a { color: #6fb0b7; }
Сам алгоритм будет достаточно простым:
- Проходимся по всем пунктам меню и для каждого считываем url, на который ведёт ссылка в нём;
- Проверяем url ссылки с url текущей страницы сайта;
- Если значения совпадают – добавляем проверяемому элементу меню класс .current, если нет – проверяем следующий элемент.
Подсветка активного пункта меню – варианты реализация
Насчёт языка реализации – проще всего обозначенный алгоритм будет реализовать на JavaScript. В частности, я буду использовать для этого популярную библиотеку jQuery.
Также можно использовать языки бэкэнда, в частности, самый популярный из них – PHP, встраивая PHP-скрипты в шаблон. Но, по мнению сторонников «чистого кода» этот подход не является оптимальным, т.к. засорять HTML-код шаблона логикой приложения – не есть хорошо.
Если же в вашем проекте используются шаблонизаторы (Smarty, Blade, Twig и др.), основным предназначением которых является как раз разделение бизнес-логики от представления за счёт введения своих конструкций, аналогичных функциям языков бкэнда, то PHP-вариант может вам подойти.
Но если проверка переменной и присвоение класса ещё можно сделать директивами шаблонизаторов (не люблю я их, кстати, т.к. не вижу большого отличия чистых php-скриптов от конструкций шаблонизатора, которые ещё выучить нужно), то получение url текущей страницы так просто не сделать.
Как альтернатива – в PHP-варианте можно было бы получение текущего url вынести в отдельный скрипт, который будет возвращать переменную с ним. А в шаблоне нужно было бы сверять с ней ссылки в пунктах меню и в зависимости от результатов присваивать им класс или нет.
Как резюме, — PHP-вариант приведёт вас к громоздкости кода шаблона или необходимости поиска требуемого php-скрипта или прописывании нового для вычисления текущего url и передачи этого значения в шаблон.
В принципе, если вас это не остановит – на PHP или другом языке бэкэнда, который используется у вас в проекте, вы уже сможете реализовать данную функцию самостоятельно, т.к. алгоритм я привел, осталось только перевести его.
Если возникнут какие-то проблемы с кодом – пишите в комментариях, буду рад вам помочь.
Кстати, при подборе ключевых слов для данной статьи, выяснилось, что некоторые люди всерьёз полагают, что выделение активного пункта меню можно сделать с помощью чистого CSS.
Но, хочу сказать, что данное предположение ошибочно, т.к. CSS – это язык оформления документа, в котором не предусмотрен функционал определения текущего url, на основании которого пункт меню может считаться активным.
Поэтому не тратьте время на поиски и используйте либо JS-вариант реализации, которая будет рассмотрена далее, либо бэкэнд-вариацию.
Подсветка активного пункта меню – jQuery реализация
Итак, давайте вместе составим наш jQuery-скрипт для выделения активного пункта меню на основании алгоритма, который был приведён выше.
Для начала создадим функцию, внутри которой мы будем писать наш код. Название для неё необязательно:
$(function () { });
Итак, первым делом, определяем url текущей страницы и записываем его в переменную для дальнейшего использования:
var location = window.location.href;
Однако, если вывести полученное значение с помощью js-функций alert() или console.log(), то мы увидим полный путь, начинающийся с указания протокола и доменного имени сайта, что нам не нужно.
Наши ссылки в главном меню содержат относительные адреса страниц в формате «/адрес_страницы», что означает их адресацию относительно корня сайта.
Поэтому наша задача – это извлечь из текущего url ту его часть, которая будет сопоставима с адресами ссылок в меню.
Для этого разбиваем url на части, которые отделены друг от друга с помощью символа слэша («/»), выбираем самую последнюю из них и прибавляем ей в начало слэш:
var cur_url = '/' + location.split('/').pop();
Если вы предполагаете использовать на своём сайте формат относительных ссылок без слэша, то добавлять его не стоит.
Также, если в качестве адресов ссылок вы хотите использовать абсолютные значения, т.е. ссылки на страницы начинаются с указания протокола и доменного имени сайта в формате «http://домен.зона/адрес_страницы», то вышенаписанная строка вам вообще не нужна.
Дальше у нас по плану проверка адресов ссылок в главном меню на соответствие с текущим url. Лучше всего делать это в цикле перебором всех пунктов главного меню.
Поскольку меню имеет class menu, то, благодаря особенностям JavaScript и jQuery, прописываем следующий код цикла.
$('.menu li').each(function () { });
Доступ к текущему элементу в таком цикле будет осуществляться с помощью конструкции $(this). Соответственно, адрес ссылки, содержащейся в пункте меню, можно получить с помощью следующего кода. Результат также, для удобства, записываем в переменную:
var link = $(this).find('a').attr('href');
Теперь главная проверка на соответствие текущего urla и прописанного в качестве адреса ссылки:
if(cur_url == link) $(this).addClass('active');
Как видите, если ссылка является текущим url, то <li> мы добавляем класс .current для подсветки активного пункта меню.
В итоге, у нас получился симпатичный и лаконичный скриптик:
$(function () { var location = window.location.href; var cur_url = '/' + location.split('/').pop(); $('.menu li').each(function () { var link = $(this).find('a').attr('href'); if (cur_url == link) { $(this).addClass('current'); } }); });
Всё, что теперь осталось для реализации подсветки активного элемента меню – это подключить скрипт на наш сайт. Если вы не знаете, как это делается, то хочу порекомендовать вам статью, где это написано, а также содержится ответ на вопрос «На чём написан сайт?».
После произведённых действий активный пункт меню должен выделяться среди остальных подобным образом:
Оставляйте ваши отзывы в комментариях, делитесь данной статьёй со своими друзьями в социальных сетях и не забывайте подписываться на обновления проекта – впереди вас ждёт ещё очень много интересного и увлекательного материала 🙂
На этом сегодняшняя статья подошла к концу. Надеюсь, она была для вас полезной.
До новых встреч 😉
P.S.: если вам нужен сайт либо необходимо внести правки на существующий, но для этого нет времени и желания, могу предложить свои услуги.
Более 5 лет опыта профессиональной разработки сайтов. Работа с PHP, OpenCart, WordPress, Laravel, Yii, MySQL, PostgreSQL, JavaScript, React, Angular и другими технологиями web-разработки.
Опыт разработки проектов различного уровня: лендинги, корпоративные сайты, Интернет-магазины, CRM, порталы. В том числе поддержка и разработка HighLoad проектов. Присылайте ваши заявки на email cccpblogcom@gmail.com.
И с друзьями не забудьте поделиться 😉
У меня вот вопрос, есть такой плагин на WordPress jquery vertical accordion, популярный довольно таки, среди сайтов использующих аккордеон меню. Плагин отличный, легкий удобный, но есть один минус у него, с которым борюсь уже несколько дней, честно — замучился, готов на стенку залезть.
Может получиться у Вас помочь мне, буду очень благодарен.
Суть в том что там, как раз вот выделение активного пункта меню и нет. Куда я только скрипт не сувал ( пытался в плагин внедрить, в шапку и т.д. ) проблема остается. По гуглив в интернете кроме кучи людей которые задают вопросы где только можно, как придать этому плагину такую возможность — нечего не нашел к сожалению.
Добрый вечер! По поводу плагина — думаю, что нужно разбираться в его коде или настройках. Сомнительно, что в ПО, отвечающем за реализацию меню, нет такой банальной возможности как выделение активного пункта.
Если не вникать в код плагина, то приведённый в статье вариант должен сработать. Единственное, нужно подстроить его под Ваш конкретный случай (прописать необходимый класс меню и учесть его структуру в целом).
Проблема в применении. Сайт у меня только в разработке, и начал с меню и уже проблема, а так все стандартное нет не каких других плагинов и тема самая довольно таки обычная.
Вот смотрите:
1. Добавил CSS класс .currenta ( current в главном меню используется ).
2. Перед добавляю скрипт
Может я класс вставляю не тот ? вот скрин: http://imgur.com/a/zsax3
Как я понимаю скрипт же ищет любой div на странице и добавляет класс к нужному элементу ?
Вы слегка не поняли принцип работы скрипта, поэтому поставили классы не так, как нужно. Вкратце ещё раз напомню алгоритм выделения активного пункта меню:
1. Определяем текущий url
2. Проходимся по пунктам меню, которые содержат ссылки на страницы
3. Проверяем ссылки с текущим url, и если совпадают, то пункту меню присваиваем класс для его выделения.
Приведённый мной код сработает, если ваше меню имеет следующую структуру:
Если оно такое же, то код для Вашего случая, с учётом присланного скриншота, будет 1-в-1 как в статье, т.к. меню оформлено в виде ul — списка с классом «menu».
Если же структура меню отличается от описанной выше, то скорректируйте код в соответствии с алгоритмом.
P.S. В статье чётко описана каждая строчка итогового блока кода, поэтому перечитайте ещё раз — это поможет проставить классы правильно.
Делал все как описано в статье. Если через инспектор элементов смотреть на меню, то вот: http://imgur.com/a/yhqBu
Но все равно не получается определиться с нужным классом, пробовал метод перебора и добавлял разные классы — не где не сработало.
А вообще стиль в плагине описан описан как #dc_jqaccordion_widget-%ID%-item
Может быть такое что в плагине дело ? Может там другие условия существуют которые влияют на это ? Там к примеру в одном файле плагина есть не что похожее на скрипт приведенный вами, с добавлением .active, но это для дочерних меню как я понял, но к сожалению код плагина разобрать не особо получается.
Судя по последнему скриншоту, который Вы прислали, у ссылки, ведущей из главного меню на страницу «Базы данных», уже установлен класс «active». Следовательно, плагин сам определяет активный пункт меню и без дополнительных скриптов.
Возможно, у Вас вообще банальные проблемы со стилями, раз активный пункт меню не выделяется среди остальных? Посмотрите стили класса active и при необходимости установите им !important после значения, чтобы перебить прочие стили.
Там с под меню есть такая вещь, открытые под меню все выделяются, при чем выделяются прям все пункты активными, если без под меню, просто выделить сами пункты меню, главные которые, без подменю, то при переходе по этим пунктам они сохраняют свое активное состояние, даже если пользователь уже давно на другой странице.
Сложно вот так на словах объяснять, может быть у Вас есть возможность посмотреть плагин ?
Может подумаете чтобы пост сделать? 🙂 Я думаю много людей будет, по мимо меня, которые будут Вам благодарны за это 🙂
Спасибо за идею 🙂 Если в данном плагине действительно есть такой баг, то я над ним с удовольствием поработаю на досуге. Подписывайтесь на обновления, чтобы быть в курсе, когда статья выйдет.
Буду очень ждать 🙂
p.s. Спасибо за Ваши труды, есть интересный материал, желаю удачи в развитии.
Большое спасибо за тёплые пожелания) А насчёт плагина не могли бы Вы уточнить, с каким именно возникли проблемы? С ним — wordpress.org/plugins/jquery-vertical-accordion-menu ?
Он самый.
А Вас не смутил тот факт, что плагин уже 2 года не обновлялся? Возможно, возникшие проблемы обусловлены именно данной особенностью. В любом случае, в ближайшее время обещаю вникнуть в него поподробнее.
Спасибо за статью, нашла много чего интересного!
как реализовать данный скрипт к многоуровневым меню? чтобы уровень страницы ещё открывался?
Если Вам нужно, чтобы, например, при переходе на какую-то статью блога с url siteurl.com/blog/post1 подсвечивался пункт меню с url siteurl.com/blog или siteurl.com/blog/, то нужен следующий код:
А возможно ли сделать так, чтоб подсвечивался только один родительский пункт меню.
например есть статья post1 c url http://www.siteurl.com/category/blog/post1 и когда открыта эта статья, чтоб был выделен только пункт меню blog.
Здравствуйте. Ответ на ваш вопрос содержится в моём комментарии выше от 24.04.2017
Я попробовал, но данный код добавляет класс ‘current’ всем родительским категориям. Т.е. например для ссылки siteurl.com/category/blog/post1 класс добавляется к категории ‘category’ и к категории ‘blog’, а я бы хотел чтоб он добавлялся именно только к последней родительской категории ‘blog’. Возможно ли это реализовать с данным кодом? Спасибо!
В таком случае, попробуйте данный код:
В данном случае у вас переменная cur_url будет содержать url текущей страницы, обрезанный до предпоследнего сегмента. Т.е. она будет содержать ссылку на страницу родительской категории. А далее данный url будет сравниваться с адресами ссылок у элементов главного меню. Вам останется только проверить, чтобы участвовавшие в сравнении url имели одинаковый формат.
Подскажите, а как реализовать активную ссылку меню, если при выборе категории есть сортировки и пагинация. Следовательно когда переходишь на другую страницу, в адресной строке добавляются параметры.
Не просто:
А вот так:
При переходе на другую страницу, ссылка уже не подсвечивается.
Добрый день! По поводу Вашей ситуации — вам нужно будет при переходе по URL получать значение GET-параметра из URL либо по его номеру (в Вашем случае за категорию отвечает первый параметр cat), либо по названию параметра.
Я лично считаю, что второй способ более правильный, т.к. более универсальный.
Путей вычисления значения GET-параметра много, но мне нравится следующий:
var location = window.location.href;
var url = new URL(location);
var cat = url.searchParams.get("cat");
С учётом данного метода итоговый код подсветки активного пункта меню с помощью jQuery в Вашем случае будет иметь примерно следующий вид:
Код примерный, т.к. я не знаю в каком формате у Вас указаны url в ссылках главного меню.
Думаю, что идею Вы поняли и подстроить приведенный код под свой сайт труда не составит.
Данный скрипт лучше помещать не в тег HEAD, а вниз документа.
Так он будет корректно работать.
Добрый день! А с чего вы взяли, что скрипт нужно помещать внутрь тэга HEAD? 🙂
В статье нет об этом ни слова.
Если уже поднимать данный вопрос, то да, скрипт должен быть после закрывающегося тэга BODY, как и весь JavaScript — код, т.к. он нужен только после загрузки страницы.
У меня схожая задача с комментарием выше, но ссылки формируются так /today/news/topic/, /yesterday/news/topic/ и тп.
Нужно подсвечивать всю ветку если человек зашел в today, то подсвечивает active, если /today/news/ то тоже подсвечивает и тд /today/news/topic/ тоже. У меня код такой, но он работает только с родителями так сказать.
Подскажите как поправить чтоб было универсально для подкаталогов.
Добрый вечер. Если я правильно понял Вашу ситуацию, то Вам поможет следующий код, который также ранее приводился в комментариях:
Да, но он у меня не работает
Проверьте имена классов меню и класса, который отвечает за подсветку.
Здравствуйте.
Последние 4 это уже пробы, и все равно не работает
В вашем случае HTML разметка меню должна быть такой, чтобы JS-код работал:
CSS стилей хватит этих (для уверенности применение стилей .active использовать атрибут !important):
Если снова подсветка активного пункта меню не заработает, то проинспектируйте HTML код нужного пункта меню и посмотрите, добавился ли к нему класс .active.
Если да — проблемы со стилями CSS. Если нет — проблема в HTML разметке или JS-коде. Возможно, действие скрипта блокируется в другом месте. В данном ситуации нужно будет изучать код самого сайта.
Разобрался, заработало, спасибо огромное!
Пожалуйста 🙂 Рад был помочь.
Добрый день! У меня тоже все работает с ссылками, в которых есть гет параметры. Но не работает, если гет параметр на кириллице. Как быть?
Здравствуйте! Если проблемы с кодировкой, то и решать их нужно проверкой кодировки 🙂 Чтобы не было проблем с кириллицей, нужно, что у всех ваших html, js, php и др. файлов были одинаковые кодировки, а именно, UTF-8. И внутри самого HTML-документа должна быть указана данная в следующем формате:
В любом случае, нужно дебажить код и смотреть, что выводится в JS на каждом этапе. Самый простой способ — вызов console.log(имя_переменной);
Доброго времени суток!
Подскажите, пожалуйста, как можно реализовать данную html-конструкцию?
Уже все перепробовал, не получается.
Добрый вечер. Вам подойдёт следующий код:
Чтобы он заработал в Вашем случае, нужно все ссылки поместить внутрь контейнера с классом menu. Либо присвоить этот класс существующему родителю. HTML вёрстка Вашего меню должна быть следующей:
Ну, и скрипт добавит к ссылке, соответствующей текущей странице, класс active, так что в CSS стилях у вас должно быть следующее правило:
Приведённый выше код сделает ссылку красного цвета. Вместо данного правила установите своё собственное, которое будет гармонично выделять активный пункт меню на фоне Вашего дизайна.
И ещё маленькая подсказка. Для внутренних страниц сайта на ссылках лучше не использовать атрибут rel=»nofollow» — его стоит использовать только на ссылках на внешние ресурсы, на которые Вы не хотите отпускать поискового робота со своего сайта, т.е. индексировать их.
Надеюсь, мой комментарий был полезен и у Вас всё получилось 🙂
Сделать подсветку в пунктах меню можно с помощью CSS ))
Можно и так. Но этот способ будет работать только на статический сайтах, где страницы не меняются динамически.
Чтобы определять текущую страницу и подсвечивать соответствующий пункт меню необходимо определять текущую страницу программно. Либо с помощью JS на стороне клиента, либо средствами backend-языков.
Спасибо за скрипт. Разобрался, очень помогло. Главное только на свежую голову разбираться. Единственное, что не смог его подключить через внешний файл, включил через футер.
Пожалуйста 🙂 Кстати, о том, как подключить внешние JavaScript скрипты на страницу, написано в этой статье.
Доброй ночи. Подскажите пожалуйста, можно ли как то подсвечивать ссылки в меню от 1 уровня вложенности до последнего? (Весь путь от начала и до конца) Так же хотел уточнить, можно ли как то в плагине pdotools настроить в pdomenu скорость перехода(открытия) ссылок меню? Спасибо !
Здравствуйте. Код, приведённый в статье, как раз и будет делать то, что Вам нужно — подсвечивать ссылку в главном элементе меню, а также во всех дочерний. Если этого не происходит, то у Вас какие-то проблема с вёрсткой или стиль для подсветки ссылок перебивается для дочерних каким-то другим.
По поводу плагина — не знаю, не сталкивался с таким.
Хотелось бы узнать какая цветовая схема используется в кодах и можно ли её установить на Sublime Text 3?
У меня для подсветки синтаксиса в коде на сайте используется WordPress плагин SyntaxHighlighter с темой RDark. В Sublime есть аналогичная. более чем уверен 🙂 Тёмный фон в редакторах кода сейчас в моде 🙂 Так что практически у всех современных IDE есть подходящие темы.
А подскажите, как реализовать то же самое , только чтобы выделялся весь путь при переходе по ссылкам меню от меню 1 уровня до последнего вложенного пункта меню? Спасибо
Простите, но не понял, что Вы хотите. Можете привести пример?
У меня есть сайт , там выпадающее меню навигации (многоуровневое) , я хочу чтобы у меня подсвечивался не только активный элемент , но и путь по дереву всему. т.е. допустим я перешел во вкладку «Услуги» потом «Проектирование зданий и сооружений» потом «Проектирование инженерных сетей» и потом остается последней вложенный элемент «Проектирование кондиционирования» . Я хочу чтобы подсвечивался не только «Проектирование кондиционирования» , но и все вкладки по которым я прошел прежде чем дошел до этого пункта меню.
Тогда Вам нужен данный вариант кода, который я уже публиковал в ответах на комментарии:
Добрый вечер!
Не могу понять как применить класс nav__list-item active-nav к родительскому пункту меню work, в случае, если активен любой из его дочерних элементов. Ну и так по аналогии с любым другим пунктом меню: применяем этот класс только к родительским, если активны дочерние. Если дочерних нет класс применяется к единственному родительскому все равно.