Сегодня мы поговорим о том как сделать подобное меню:


И в дополнение разберем небольшой скрипт который позволит меню понимать где мы находимся и подсвечивать нужный пункт меню.
Итак, для начала я добавлю разметку:
<div class="block one"> Главная</div>
<div class="block two"> Услуги</div>
<div class="block three">Преимущества</div>
<div class="block four">Обратная связь</div>
Конечно, у вас это могут быть совершенно любые блоки, а я же просто задам им некоторые стили, что бы мы могли их отличить:
.block{
height: 1000px;
width: 100%;
text-align: center;
font-size: 24px;
color: #FFF;
padding: 40px 0;
}
/* Для каждого блока свой цвет: */
.one{
background: #000;
}
.two{
background: #939346;
}
.three{
background: #CC6633;
}
.four{
background: #33CC66;
}
Да, те кто уже делал менюшки не раз, может показаться, что она слишком нагромождена, но уверяю вас, тут нет ничего лишнего. Такая разметка хоть и необычная, но зато позволяет нам комфортно ее редактировать и менять так как нам вздумается. Что ж, а теперь рассмотрим стили, тут стоит остановиться несколько подробнее для понимания того, как можно измениnь подобное меню под себя.
.menu_right {
position: fixed; /*Задаем фиксированную позицию */
top: 35%; /*Задаем расстояние сверху на котором будет наше меню*/
right: 40px;/*Задаем расстояние справа(или слева, если ваше меню должно быть слева)*/
}
.menu_right ul {
list-style-type: none;/*Убираем свойства маркированного списка */
height: 250px;/*Задаем высоту */
display: flex;/*Задаем для того что бы мы могли легко и просто манипулировать положением li */
flex-direction: column;/*Делаем меню вертикально*/
justify-content: space-evenly;/*И задаем расстояние между объектами */
}
.menu_right ul li {
position: relative;/*Относительно li будут располагаться div с пунктом меню */
}
.menu_right ul li a span {
display: block;
background-color: #8bc34a;/*Цвет для span*/
width: 15px;/*Ширина для span*/
height: 15px;/*Высота для span*/
transform: rotate(45deg);/*Поворот span */
}
.menu_right ul li a:hover span {
background-color: #dadada;/*Цвет для span при наведении на него*/
box-shadow: 0px 0px 14px 4px #dadada;/*Тень для span при наведении на него*/
transform: rotate(45deg);/*Поворот span */
}
.menu_right ul li a div {
position: absolute;/*Положение задается относительно li*/
right: 30px;/*Справа относительно li*/
top: -10px;/*Сверху относительно li*/
height: 0;
opacity: 0;
overflow: hidden;/*Данные пункты позволяют нам полность скрыть пункты меню, высвечивающиеся при наведении*/
border-radius: 5px;/*Обычное закругление углов div*/
transition: opacity 1.5s;/*Время проявление div при наведении*/
}
.menu_right ul li a:hover>div {
position: absolute;/*Положение задается относительно li*/
right: 30px;/*Справа относительно li*/
top: -10px;/*Сверху относительно li*/
opacity: 1;/*Делаем проявление div при наведении*/
padding: 8px 25px;
color: #fff;/*Цвет текста*/
overflow: visible;
background-color: #0a5014;/*Цвет фона div*/
border: 1px solid #9e9e9e;/*Цвет border*/
border-radius: 5px;/*Обычное закругление углов div*/
white-space: pre;/*для правильной адаптации текста*/
height: 20px;/*Высота div*/
font-size: 18px;/*Размер шрифта*/
}
При желании пункты меню можно сделать круглыми:

.menu_right ul li a span {
display: block;
background-color: #dadada;/*Цвет для span*/
width: 10px;/*Ширина для span*/
height: 10px;/*Высота для span*/
border-radius: 10px;/*Закругление*/
box-shadow: 0px 0px 14px 4px #dadada;/*Тень для span*/
}
.menu_right ul li a:hover span {
background-color: #8bc34a;/*Цвет для span при наведении на него*/
box-shadow: 0px 0px 14px 4px #dadada;/*Тень для span при наведении на него*/
}
Теперь, когда вы разобрались как легко создавать подобные меню, мне бы хотел поговорить, о том что я упоминал в начале. Как же объяснить менюшки где какой блок? Как заставить ее реагировать?
Для начала мы добавим следующие якоря, для того чтобы можно было удобно переходить по секциям:
<a name="main"></a>
Получается следующее:
<div class="block one">
<a name="main"></a>
Главная
</div>
<div class="block two">
<a name="service"></a>
Услуги
</div>
<div class="block three">
<a name="advantage"></a>
Преимущества
</div>
<div class="block four">
<a name="feedback"></a>
Обратная связь
</div>
Теперь для ссылок в меню мы добавим href="" с определенным названием соответствующим названию секции:
Якорь в секции: <a name="main"></a> === Сcылка в меню:<a href="#main"></a>
<li class="menu_right__li">
<a href="#main" class="active">
<div class="menu_right__div">Главная</div>
<span></span>
</a>
</li>
<li class="menu_right__li">
<a href="#service" >
<div class="menu_right__div">Услуги</div>
<span></span>
</a>
</li>
<li class="menu_right__li">
<a href="#advantage">
<div class="menu_right__div">Преимущества</div>
<span></span>
</a>
</li>
<li class="menu_right__li">
<a href="#feedback">
<div class="menu_right__div">Обратная связь</div>
<span></span>
</a>
</li>
Что ж, переходы по блокам мы реализовали, но нам бы хотелось что бы при нахождении на нужной секции подсвечивался пункт меню. Тут одними средствами html/css уже не обойтись. Но, не стоит переживать, просто посмотрите на этот код:
window.addEventListener('scroll', () => {
//Добавляем обработчик события "скролл" на окно браузера
let scrollDistance = window.scrollY;
//Определяем на сколько документ пролистали в данный момент по вертикали и записываем
//это в переменную scrollDistance
if (window.innerWidth > 768) {//Если ширина больше 768px, то будет срабатывать
//следующий код(я не использовал данное меню на устройствах с шириной менее 768,
//так как это становится не удобным, но вы при большом желании можете его адаптировать)
document.querySelectorAll('.block').forEach((el, i) => {
//Получаем нужные секции(в моем примере это просто divы с классом "block", используем
//цикл forEach для перебора элементов, учитывая как сам элемент- "el",
//так и его порядковый номер - "i")
if (el.offsetTop <= scrollDistance + 150) {
// если расстояние до верхней границы конкретной секции(та секция до которой мы
//доскроллили)меньше чем scrollDistance + 150, тогда мы запускаем цикл forEach для
//a(ссылок)
document.querySelectorAll('.menu_right__ul>li>a').forEach((el) => {
if (el.classList.contains('active')) {
//проверяем при скролле все ссылки и если ссылка уже имеет класс 'active',
//то убираем его
el.classList.remove('active');
}
});
document.querySelectorAll('.menu_right__ul li')[i].querySelector('a').classList.add('active');
//Берем порядковый номер конкретной секции и добавляем ей класс 'active'
}
});
}
Теперь у нас при скролле или переходе на ту или иную секцию будет добавляться к ссылке(соответствующей данной секции) класс "active" который мы легко использовать в наших целях. Например(для подсветки пункта меню на котором мы находимся):
.menu_right ul li a.active span{
background-color: #dadada;/*Цвет для span */
box-shadow: 0px 0px 14px 4px #dadada;/*Тень для span*/
transform: rotate(45deg);/*Поворот span */
}


Надеюсь я достаточно подробно все расписал и у вас не возникло проблем с реализацией подобного меню в своих проекта. Если остались вопросы пишите в комментарии, все обсудит и рассмотрим.
Ссылка на весь код на git-hub https://github.com/b4dmilk/fixed_menu,
Ссылка на весь код на codepen https://codepen.io/Badmilk/pen/oNymyvB