Меню с изменяемым состоянием может применяться для различных задач, в т.ч. для меню лэндинга или для оглавления длинной страницы. Такое меню состоит из хэш-ссылок для перемещения по самой странице. Смысл в том, чтобы при перемещении по различным блокам соответствующий пункт меню изменялся.
Меню лэндинга
Верста максимально проста и коротка
<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]
