Выделение активного пункта меню с помощью jQuery

Автор: | 18.09.2016

vydelenie-aktivnogo-punkta-menu-s-pomoschu-jqueryДоброго времени суток :-)

Сегодня мы поговорим о довольно тривиальной задаче – выделении активного пункта меню с помощью jQuery.

Для начала, традиционно, пару слов о том, кому будет полезна данная информация.

В первую очередь, сегодняшняя статья будет бесценной для тех, кто решил создать сайт «с нуля» на чистом php+css+html+javascript или с помощью фреймворков.

Бесценна – потому что в этом случае у вас не будет готового функционала, как у любителей CMS, поэтому выделение активного пункта меню придётся реализовывать самостоятельно.

Но, если вы всё-таки относитесь к фанатам создания сайта на CMS, где данный функционал доступен «из коробки», приводимая далее информация не будет такой уж бесполезной, т.к. никто не сможет вам гарантировать, что устанавливаемый графический шаблон будет без багов :-)

А бывает, что после установки какого-то модуля, ломается уже существующий функционал…

В общем, принципы организации подсветки активного пункта меню будут полезны всем, без исключения.

К тому же, стоит подчеркнуть, что рассматриваемый нами сегодня способ является кроссплатформенным, поэтому он подойдёт он всем без исключения.

Итак, переходим от лирики к практике.

Постановка задачи

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

Итак, у нас есть главное меню сайта, которое состоит из пунктов, содержащих ссылки на страницы сайта.

Пункты меню, соответственно, имеют названия, созвучные с названиями страниц сайта.

Для примера возьмём главное меню, характерное для сайтов-визиток:

nepravilnoe-vydelenie-aktivnogo-punkta-menu

Как видно на картинке, меню в нашем случае состоит из следующих элементов:

  • 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;
}

Сам алгоритм будет достаточно простым:

  1. Проходимся по всем пунктам меню и для каждого считываем url, на который ведёт ссылка в нём;
  2. Проверяем url ссылки с url текущей страницы сайта;
  3. Если значения совпадают – добавляем проверяемому элементу меню класс .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. Лучше всего делать это в цикле перебором всех пунктов главного меню.

Поскольку меню имеет id=«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');
        }
    });
});

Всё, что теперь осталось для реализации подсветки активного элемента меню – это подключить скрипт на наш сайт. Если вы не знаете, как это делается, то хочу порекомендовать вам статью, где это написано, а также содержится ответ на вопрос «На чём написан сайт?».

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

rabochee-vydelenie-aktivnogo-punkta-menu

Оставляйте ваши отзывы в комментариях, делитесь данной статьёй со своими друзьями в социальных сетях и не забывайте подписываться на обновления проекта – впереди вас ждёт ещё очень много интересного и увлекательного материала :-)

На этом сегодняшняя статья подошла к концу. Надеюсь, она была для вас полезной.

До новых встреч 😉

  1. 5
  2. 4
  3. 3
  4. 2
  5. 1
9 голосов, в среднем: 5 из 5

27 комментариев к статье "Выделение активного пункта меню с помощью jQuery"

  1. Виталий

    У меня вот вопрос, есть такой плагин на WordPress jquery vertical accordion, популярный довольно таки, среди сайтов использующих аккордеон меню. Плагин отличный, легкий удобный, но есть один минус у него, с которым борюсь уже несколько дней, честно — замучился, готов на стенку залезть.
    Может получиться у Вас помочь мне, буду очень благодарен.
    Суть в том что там, как раз вот выделение активного пункта меню и нет. Куда я только скрипт не сувал ( пытался в плагин внедрить, в шапку и т.д. ) проблема остается. По гуглив в интернете кроме кучи людей которые задают вопросы где только можно, как придать этому плагину такую возможность — нечего не нашел к сожалению.

    1. Pashaster Автор

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

      Если не вникать в код плагина, то приведённый в статье вариант должен сработать. Единственное, нужно подстроить его под Ваш конкретный случай (прописать необходимый класс меню и учесть его структуру в целом).

      1. Виталий

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

        Вот смотрите:
        1. Добавил CSS класс .currenta ( current в главном меню используется ).
        2. Перед добавляю скрипт

        $(function () {
        var location = window.location.href;
        var cur_url = ‘/’ + location.split(‘/’).pop();
        $(‘dcjq-accordion’).each(function () {
        var link = $(this).find(‘a’).attr(‘href’);
        if(cur_url == link) $(this).addClass(‘currenta’);
        });
        });

        Может я класс вставляю не тот ? вот скрин: http://imgur.com/a/zsax3
        Как я понимаю скрипт же ищет любой div на странице и добавляет класс к нужному элементу ?

        1. Pashaster Автор

          Вы слегка не поняли принцип работы скрипта, поэтому поставили классы не так, как нужно. Вкратце ещё раз напомню алгоритм выделения активного пункта меню:

          1. Определяем текущий url
          2. Проходимся по пунктам меню, которые содержат ссылки на страницы
          3. Проверяем ссылки с текущим url, и если совпадают, то пункту меню присваиваем класс для его выделения.

          Приведённый мной код сработает, если ваше меню имеет следующую структуру:

          <ul>
          <li>
          <a href="ссылка на страницу1" rel="nofollow">Страница1</a>
          </li>
          ...
          </ul>
          

          Если оно такое же, то код для Вашего случая, с учётом присланного скриншота, будет 1-в-1 как в статье, т.к. меню оформлено в виде ul — списка с классом «menu».

          Если же структура меню отличается от описанной выше, то скорректируйте код в соответствии с алгоритмом.

          P.S. В статье чётко описана каждая строчка итогового блока кода, поэтому перечитайте ещё раз — это поможет проставить классы правильно.

          1. Виталий

            Делал все как описано в статье. Если через инспектор элементов смотреть на меню, то вот: http://imgur.com/a/yhqBu

            Но все равно не получается определиться с нужным классом, пробовал метод перебора и добавлял разные классы — не где не сработало.
            А вообще стиль в плагине описан описан как #dc_jqaccordion_widget-%ID%-item

            Может быть такое что в плагине дело ? Может там другие условия существуют которые влияют на это ? Там к примеру в одном файле плагина есть не что похожее на скрипт приведенный вами, с добавлением .active, но это для дочерних меню как я понял, но к сожалению код плагина разобрать не особо получается.

          2. Pashaster Автор

            Судя по последнему скриншоту, который Вы прислали, у ссылки, ведущей из главного меню на страницу «Базы данных», уже установлен класс «active». Следовательно, плагин сам определяет активный пункт меню и без дополнительных скриптов.
            Возможно, у Вас вообще банальные проблемы со стилями, раз активный пункт меню не выделяется среди остальных? Посмотрите стили класса active и при необходимости установите им !important после значения, чтобы перебить прочие стили.

  2. Виталий

    Там с под меню есть такая вещь, открытые под меню все выделяются, при чем выделяются прям все пункты активными, если без под меню, просто выделить сами пункты меню, главные которые, без подменю, то при переходе по этим пунктам они сохраняют свое активное состояние, даже если пользователь уже давно на другой странице.
    Сложно вот так на словах объяснять, может быть у Вас есть возможность посмотреть плагин ?
    Может подумаете чтобы пост сделать? :) Я думаю много людей будет, по мимо меня, которые будут Вам благодарны за это :)

      1. Виталий

        Буду очень ждать :)
        p.s. Спасибо за Ваши труды, есть интересный материал, желаю удачи в развитии.

        1. Pashaster Автор

          Большое спасибо за тёплые пожелания) А насчёт плагина не могли бы Вы уточнить, с каким именно возникли проблемы? С ним — wordpress.org/plugins/jquery-vertical-accordion-menu ?

          1. Pashaster Автор

            А Вас не смутил тот факт, что плагин уже 2 года не обновлялся? Возможно, возникшие проблемы обусловлены именно данной особенностью. В любом случае, в ближайшее время обещаю вникнуть в него поподробнее.

  3. Бурылёва Ксения

    Спасибо за статью, нашла много чего интересного!

  4. Vladimir

    как реализовать данный скрипт к многоуровневым меню? чтобы уровень страницы ещё открывался?

    1. Pashaster Автор

      Если Вам нужно, чтобы, например, при переходе на какую-то статью блога с url siteurl.com/blog/post1 подсвечивался пункт меню с url siteurl.com/blog или siteurl.com/blog/, то нужен следующий код:

      $(function () {
          var location = window.location.href;
       
          $('.menu li').each(function () {
              var link = $(this).find('a').attr('href');
       
              if (location.indexOf(link) !== -1)
              {
                  $(this).addClass('current');
              }
          });
      });
      
  5. Михаил

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

    http://site.ru/category.php?cat='kond'

    А вот так:

    http://site.ru/category.php?cat='kond'&sort='123'&page='2'

    При переходе на другую страницу, ссылка уже не подсвечивается.

    1. Pashaster Автор

      Добрый день! По поводу Вашей ситуации — вам нужно будет при переходе по URL получать значение GET-параметра из URL либо по его номеру (в Вашем случае за категорию отвечает первый параметр cat), либо по названию параметра.

      Я лично считаю, что второй способ более правильный, т.к. более универсальный.

      Путей вычисления значения GET-параметра много, но мне нравится следующий:

      var location = window.location.href;
      var url = new URL(location);
      var cat = url.searchParams.get("cat");

      С учётом данного метода итоговый код подсветки активного пункта меню с помощью jQuery в Вашем случае будет иметь примерно следующий вид:

      $(function () {
          var location = window.location.href;
      
          var cur_url = new URL(location);
          var cur_category = cur_url.searchParams.get('cat');
       
          $('.menu li').each(function () {
              var link = $(this).find('a').attr('href');
              var link_url = new URL(link);
              var link_category = link_url.searchParams.get('cat');
      
              if (cur_category == link_category)
              {
                  $(this).addClass('current');
              }
          });
      });
      

      Код примерный, т.к. я не знаю в каком формате у Вас указаны url в ссылках главного меню.

      Думаю, что идею Вы поняли и подстроить приведенный код под свой сайт труда не составит.

  6. Семен

    Данный скрипт лучше помещать не в тег HEAD, а вниз документа.
    Так он будет корректно работать.

    1. Pashaster Автор

      Добрый день! А с чего вы взяли, что скрипт нужно помещать внутрь тэга HEAD? :-)

      В статье нет об этом ни слова.

      Если уже поднимать данный вопрос, то да, скрипт должен быть после закрывающегося тэга BODY, как и весь JavaScript — код, т.к. он нужен только после загрузки страницы.

  7. Alexandr

    У меня схожая задача с комментарием выше, но ссылки формируются так /today/news/topic/, /yesterday/news/topic/ и тп.

    Нужно подсвечивать всю ветку если человек зашел в today, то подсвечивает active, если /today/news/ то тоже подсвечивает и тд /today/news/topic/ тоже. У меня код такой, но он работает только с родителями так сказать.

    $(document).ready(function(){
    $('.nav-menu li a').each(function () {
            var location = window.location.href;
            var link = this.href; 
            if(location == link) {
                $(this).addClass('active');
            }
        });
    });
    

    Подскажите как поправить чтоб было универсально для подкаталогов.

    1. Pashaster Автор

      Добрый вечер. Если я правильно понял Вашу ситуацию, то Вам поможет следующий код, который также ранее приводился в комментариях:

      $(document).ready(function () {
          var location = window.location.href;
        
          $('.nav-menu li').each(function () {
              var link = $(this).find('a').attr('href');
        
              if (location.indexOf(link) !== -1)
              {
                  $(this).addClass('active');
              }
          });
      });
      
        1. Pashaster Автор

          Проверьте имена классов меню и класса, который отвечает за подсветку.

          1. Alexandr

            Здравствуйте.

            <a href="/today/" rel="nofollow">24 часа</a>
            <a href="/yesterday/" rel="nofollow">Вчера</a>
            
            .nav-menu > li {position:relative; float:left;margin-top:10px;}
            .nav-menu > li > a {display:block; line-height:40px; margin: 0 20px 0 0;
            color:#111; text-transform:uppercase; font-size:14px;font-weight:bold; text-align: center;}
            .nav-menu > li > a.active {color:#ff4400;}
            
            .active {color:#ff4400;}
            a .active {color:#ff4400;}
            ul.nav-menu li a .active {color:#ff4400;}
            ul.nav-menu li a.active {color:#ff4400;}
            

            Последние 4 это уже пробы, и все равно не работает

          2. Pashaster Автор

            В вашем случае HTML разметка меню должна быть такой, чтобы JS-код работал:

            <ul class="nav-menu">
                <li>
                    <a href="/today/" rel="nofollow">24 часа</a>
                </li>
            
                <li>
                    <a href="/yesterday/" rel="nofollow">Вчера</a>
                <li>
            </ul>
            

            CSS стилей хватит этих (для уверенности применение стилей .active использовать атрибут !important):

            .nav-menu > li {position:relative; float:left;margin-top:10px;}
            .nav-menu > li > a {display:block; line-height:40px; margin: 0 20px 0 0;
            color:#111; text-transform:uppercase; font-size:14px;font-weight:bold; text-align: center;}
            .nav-menu > li > a.active {color:#ff4400 !important;}
            

            Если снова подсветка активного пункта меню не заработает, то проинспектируйте HTML код нужного пункта меню и посмотрите, добавился ли к нему класс .active.

            Если да — проблемы со стилями CSS. Если нет — проблема в HTML разметке или JS-коде. Возможно, действие скрипта блокируется в другом месте. В данном ситуации нужно будет изучать код самого сайта.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *