Меню с изменяемым состоянием может применяться для различных задач, в т.ч. для меню лэндинга или для оглавления длинной страницы. Такое меню состоит из хэш-ссылок для перемещения по самой странице. Смысл в том, чтобы при перемещении по различным блокам соответствующий пункт меню изменялся.
Меню лэндинга
Верста максимально проста и коротка
<ul id="land-menu"> <li class="punkt-action"><a href="#">Главная</a></li> <li><a href="#features-block">Преимущества</a></li> <li><a href="#testing">Двигающиеся объекты</a></li> <li><a href="#forma">Forma</a></li> <li><a href="#promo">Man is the cruelest animal</a></li> </ul>
CSS
/* Меню лэндинга */ #land-menu {position: fixed; z-index: 100; top: 40%; left: 25px;} #land-menu li {list-style: none;} #land-menu li a { float: left; background-color: rgba(0, 0, 0, 0.8); margin-bottom: 5px; padding: 5px 15px; border-radius: 3px; color: #fff; width: 100%; /* пункты одинаковой ширины */ position: relative; } #land-menu li a:hover {background-color: #000;} /* #land-menu .punkt-action a {background-color: #ff5a00 !important;} выделение цветом фона текста */ /* точка */ #land-menu a:before { content: " "; border-radius: 50%; position: absolute; z-index: 1; height: 4px; width: 4px; border: 0; background: #000; left: -10px; top: 50%; margin: -2px 0 0 -2px; -webkit-transition: all .3s ease-in-out; -moz-transition: all .3s ease-in-out; -o-transition: all .3s ease-in-out; transition: all .3s ease-in-out; } #land-menu li a:hover:before { height: 12px; width: 12px; margin: -6px 0 0 -6px; border-radius: 100%; } #land-menu .punkt-action a:before { background-color: #ff5a00 !important; height: 12px; width: 12px; margin: -6px 0 0 -6px; border-radius: 100%; }
Скрипт (не нужно подключать никаких библиотек, как со scrollspy)
$(document).ready(function() { // Cache selectors var lastId, topMenu = $("#land-menu"), topMenuHeight = topMenu.outerHeight() + 15, // All list items menuItems = topMenu.find("a"), // Anchors corresponding to menu items scrollItems = menuItems.map(function() { var item = $($(this).attr("href")); if (item.length) { return item; } }); // Bind click handler to menu items // so we can get a fancy scroll animation menuItems.click(function(e) { var href = $(this).attr("href"), offsetTop = href === "#" ? 0 : $(href).offset().top - topMenuHeight + 1; $('html, body').stop().animate({ scrollTop: offsetTop }, 300); e.preventDefault(); }); // Bind to scroll $(window).scroll(function() { // Get container scroll position var fromTop = $(this).scrollTop() + topMenuHeight; // Get id of current scroll item var cur = scrollItems.map(function() { if ($(this).offset().top < fromTop) return this; }); // Get the id of the current element cur = cur[cur.length - 1]; var id = cur && cur.length ? cur[0].id : ""; if (lastId !== id) { lastId = id; // Set/remove active class menuItems .parent().removeClass("punkt-action") .end().filter("[href='#" + id + "']").parent().addClass("punkt-action"); } }); });
Если мы делаем слайды во всю высоту экрана (min-height: 100vh;), то для нормального скроллинга нужно убрать компенсацию высоты из этой строки:
offsetTop = href === '#' ? 0 : jQuery(href).offset().top - topMenuHeight + 1;
Динамическое формирование меню
Для универсальности данного функционала, необходим алгоритм динамического формирования меню. Либо по заголовкам h2, либо по блокам с id содержащихся в определенном контейнере.
Для того чтобы отследить блоки лэндинга и сформировать из них меню нужно следующее:
1. Обвести все блоки лэндинга общим блоком с id=»landing».
2. Каждому блоку лэндинга задать уникальный id и атрибут title, в котором будет прописан пункт меню
3. Создаем после открывающего тэга body div id=»land-menu-container»
4. Включаем скрипт, обязательно перед предыдущим скриптом
/* Автоматическое создание меню лэндинга */ $(document).ready(function() { var ToC = "<ul id='land-menu'>"; var newLine, el, title, link; $("#landing > div").each(function() { el = $(this); title = el.attr("title"); link = "#" + el.attr("id"); newLine = "<li>" + "<a href='" + link + "'>" + title + "</a>" + "</li>"; ToC += newLine; }); ToC += "</ul>"; $("#land-menu-container").prepend(ToC); $("#land-menu > li:first-child").addClass("punkt-action"); });
Автоматическое оглавление
Данный метод jquery (из предыдущего пункта) мы можем применить для автоматического построения оглавления.
Первым делом отыскиваем все h2 в области #post-content и присваиваем им автоматические id
$(document).ready(function() { var num=1; $("#post-content h2").each(function() { $(this).attr('id', 'title-' + num); num++; }); });
А после этого, формируем оглавление
$(document).ready(function() { var ToC = "<nav role='navigation' class='table-of-contents'>" + "<ul>"; var newLine, el, title, link; $("#post-content h2").each(function() { el = $(this); title = el.text(); link = "#" + el.attr("id"); newLine = "<li>" + "<a href='" + link + "'>" + title + "</a>" + "</li>"; ToC += newLine; }); ToC += "</ul>" + "</nav>"; $("#all-titles").prepend(ToC); });
Где-то в верстке необходимо создать div с id=»all-titles». Наилучший вариант вывести его в sitebar напрямую, либо в виде виджета. При этом сайтбар лучше сделать фиксированным, чтоб навигация по содержанию всегда была под рукой.
Проверка: есть ли h2
Можно запрограммировать чтоб блок Оглавление автоматически выводился перед статьей либо в области виджетов. При этом, данный блок можно оформить и задать ему заголовок — Содержание статьи. Но нужна проверка — выводить оглавление только в том случае если есть h2 заголовки. Для этого оборачиваем весь прошлый скрипт (кроме $(document).ready(function()) конструкцией проверки:
if( $('#post-content h2').length ) { основной скрипт оглавления }
А в абзац var ToC = добавить после строки nav еще одну строку:
"<p>Оглавление</p>" +
Тэги: меню
[site-socialshare]