Как стать автором
Обновить

Простое фиксированное меню

CSS *HTML *JavaScript *
Ожидает приглашения

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

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

Итак, для начала я добавлю разметку:

<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

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.