В этой статье я покажу, как сделать несложное бургер-меню для сайта, которое в дальнейшем вы сможете стилизовать и улучшать по своему усмотрению. Наше меню адаптируется под мобильные устройства. При нажатии на иконку-бургер, слева направо выпадает меню. Анимируется сама иконка, из бургера она превращается в крестик. Также наша навигация всегда прижата к верхней стороне браузера, что удобно для пользователей.

Скачать актуальный код бургер-меню для сайта можно здесь.

Это изображение имеет пустой атрибут alt; его имя файла - bandicam_2022-03-15_15-36-22-217-1.gif

HTML-разметка бургер-меню

Теперь давайте разберем по порядку как это сделать. Начнем с разметки HTML.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <link rel="stylesheet" href="reset.css" />
    <link rel="stylesheet" href="style.css" />
    <title>Adaptive header for site</title>
  </head>
  <body>
    <nav class="navbar">
      <div class="container">
        <div class="navbar__wrap">
          <div class="hamb">
            <div class="hamb__field" id="hamb">
              <span class="bar"></span> <span class="bar"></span>
              <span class="bar"></span>
            </div>
          </div>
          <a href="#" class="logo" id="logo">Logo</a>
          <ul class="menu" id="menu">
            <li><a href="#">Home</a></li>
            <li><a href="#">Benefits</a></li>
            <li><a href="#">Prices</a></li>
            <li><a href="#">Blog</a></li>
            <li><a href="#">About us</a></li>
            <li><a href="#">Contact</a></li>
          </ul>
        </div>
      </div>
    </nav>
    <div class="popup" id="popup"></div>
    <!-- Продолжение вашего кода .. -->
  </body>
</html>

Вся основная разметка меню содержится в элементе с классом navbar. Внутри мы располагаем контейнер с классом container для того, чтобы ограничить нашу навигацию по ширине 1000px и выровнять по центру.

Элемент navbar__wrap также является контейнером, но в нем мы уже выравниваем элементы внутри самого меню. Внутри меню содержится:

  • Сама кнопка бургер меню — div с классом hamb
  • Логотип — ссылка с классом logo
  • Элементы меню — список с классом menu

Последний div с классом popup — это всплывающее окно, которое будет появляться при нажатии на иконку бургер.

Как видите разметка довольна простая, теперь приходим к стилизации.

Стилизация бургер-меню

В начале стилизуем десктопное меню:

@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap");

html {
  box-sizing: border-box;
  height: 100%;
}

*,
*::after,
*::before {
  box-sizing: inherit;
}

body {
  display: flex;
  flex-direction: column;
  font-family: "Roboto", sans-serif;
  font-size: 16px;
  line-height: 1.2;
  height: 100%;
}

.container {
  width: 100%;
  max-width: 1000px;
  margin: 0 auto;
  height: 100%;
  padding: 0 15px;
}

.navbar {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 75px;
  background: #7a52b3;
}

.navbar__wrap {
  display: flex;
  justify-content: space-between;
  height: 100%;
}

.hamb {
  display: none;
}

.popup {
  display: none;
}

.logo {
  text-decoration: none;
  color: #fff;
  font-size: 20px;
  font-weight: bold;
  text-transform: uppercase;
  display: flex;
  align-items: center;
}

.menu > li > a {
  text-decoration: none;
}

.navbar__wrap .menu {
  display: flex;
}

.navbar__wrap .menu > li {
  display: flex;
  align-items: stretch;
}

.navbar__wrap .menu > li > a {
  display: flex;
  align-items: center;
  padding: 0 20px;
  color: rgba(255, 255, 255, 0.7);
}

.navbar__wrap .menu > li > a:hover {
  color: rgba(255, 255, 255, 1);
}

За ширину бургер меню отвечает элемент container, а конкретно его CSS-свойство max-width: 1000px. В элементе navbar мы задаем высоту height: 75px, а также делаем наше меню фиксированным благодаря свойству position: fixed.

В контейнере navbar__wrap мы распределяем все элементы меню (иконка, логотип, ссылки) равномерно, используя flexbox и его свойство justify-content: space-between.

По умолчанию элементы hamb и popup скрыты display: none. Свойство display мы будем менять в JavaScript.

Остальная часть CSS-кода не требует объяснения: там мы начиная с элемента logo стилизуем элементы нашего меню.

Делаем адаптацию под мобильную версию

Наше меню преобразуется в мобильную версию, когда ширина экрана становится меньше 1000px. В CSS это делается так:

@media (max-width: 1000px) {
  .navbar__wrap .menu {
    display: none;
  }

  .hamb {
    display: flex;
    align-items: center;
  }

  .hamb__field {
    padding: 10px 20px;
    cursor: pointer;
  }

  .bar {
    display: block;
    width: 30px;
    height: 3px;
    margin: 6px auto;
    background-color: #fff;
    transition: 0.2s;
  }

  .popup {
    position: fixed;
    top: 75px;
    left: -100%;
    width: 100%;
    height: 100%;
    background-color: #fff;
    z-index: 100;
    display: flex;
    transition: 0.3s;
  }

  .popup.open {
    left: 0;
  }

  .popup .menu {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: start;
    padding: 50px 0;
    overflow: auto;
  }

  .popup .menu > li {
    width: 100%;
  }

  .popup .menu > li > a {
    width: 100%;
    display: flex;
    justify-content: center;
    padding: 20px 0;
    font-size: 20px;
    font-weight: bold;
    color: #3f3f3f;
  }

  .popup .menu > li > a:hover {
    background-color: rgba(122, 82, 179, 0.1);
  }

  .hamb__field.active .bar:nth-child(2) {
    opacity: 0;
  }

  .hamb__field.active .bar:nth-child(1) {
    transform: translateY(8px) rotate(45deg);
  }

  .hamb__field.active .bar:nth-child(3) {
    transform: translateY(-8px) rotate(-45deg);
  }

  body.noscroll {
    overflow: hidden;
  }
}

Медиазапрос @media (max-width: 1000px) меняет стили элементов при ширине экрана меньше 1000px. Кстати, чтобы он срабатывал необходимо в HTML-разметку тега head добавить:

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

Для всплывающего окна popup мы задаем свойство left: -100%, чтобы скрыть его в левой части. При нажатии на иконку бургер к попапу добавится класс active и свойство left будет равным 0. То есть наш попап открывается слева направо. А чтобы он делал это плавно мы добавили к popup свойство transition: 0.3s.

Также при вызове popup мы блокируем прокрутку экрана у глобального тега body. Для этого добавляем ему класс body.noscroll со значением overflow: hidden.

Пишем скрипт для бургер-меню

Все подготовительные работы выполнены, осталось только «оживить» наше меню. Воспользуемся следующим кодом на JS:

const hamb = document.querySelector("#hamb");
const popup = document.querySelector("#popup");
const body = document.body;

// Клонируем меню, чтобы задать свои стили для мобильной версии
const menu = document.querySelector("#menu").cloneNode(1);

// При клике на иконку hamb вызываем ф-ию hambHandler
hamb.addEventListener("click", hambHandler);

// Выполняем действия при клике ..
function hambHandler(e) {
  e.preventDefault();
  // Переключаем стили элементов при клике
  popup.classList.toggle("open");
  hamb.classList.toggle("active");
  body.classList.toggle("noscroll");
  renderPopup();
}

// Здесь мы рендерим элементы в наш попап
function renderPopup() {
  popup.appendChild(menu);
}

// Код для закрытия меню при нажатии на ссылку
const links = Array.from(menu.children);

// Для каждого элемента меню при клике вызываем ф-ию
links.forEach((link) => {
  link.addEventListener("click", closeOnClick);
});

// Закрытие попапа при клике на меню
function closeOnClick() {
  popup.classList.remove("open");
  hamb.classList.remove("active");
  body.classList.remove("noscroll");
}

В начале мы поочередно считываем наши элементы, обращаясь к id каждого из них. Единственная особенность — в третьей строке мы клонируем menu, причем вместе со всеми его дочерними элементами. Для этого пользуемся методом cloneNode(1). Это делается для того, чтобы меню в десктопной и мобильной версии имели каждый свои стили.

Далее на иконку hamb навешиваем обработчик события на клик. При клике будем вызывать функцию hambHandler. В данной функции мы будем переключать стили у соответствующих элементов. Например: при первом нажатии на иконку для popup зададим класс active, таким образом наше всплывающее окно откроется плавно слева направо. В конце функции hambHandler мы вызовем другую функцию renderPopup, которая займется заполнением попапа.

После того, как пользователь нажмет на элемент меню, необходимо, чтобы всплывающее окно закрылось. Для этого, начиная с 27 строчки мы считаем все дочерние элементы меню. Для каждого из них навешиваем обработчик события при клике. После чего при клике выполним функцию closeOnClick, которая закроет всплывающее окно.

 

Комментарии

16

Без регистрации и смс

  • Прекрасная статья, отличное изложение, лаконичная и чёткая вёрстка.

    Автору — респект и удачи. С благодарностью забираю себе исходники.

    • Ivan:

      Нажатие эмулирует мышку в мобильной версии. Так что на короткое время, но hover всё равно сработает 🙂

  • Макс:

    хорошая статься!!

  • Вадич:

    Отличная статья, спасибо большое!

  • Кирилл:

    Я по гайду шел шаг за шагом но как только дошло до js сразу ступор…

    Uncaught TypeError: Cannot read properties of null (reading ‘cloneNode’) это выдает в консоли DevTool

    const menu = document.querySelector(«#menu»).cloneNode(1); вот на эту строчку кода ругается… Я в растерянности.

    • Антон Колесников:

      Он ругается на то, что не может считать элемент с id menu. Проверь в HTML-разметке присвоил ли ты списку id=»menu».

  • Елена:

    огромное спасибо! очень интересно!

  • Елена:

    огромное спасибо! очень интересно!

  • Ivan:

    Спасибо огромное!

    Ваш труд не оценим!

  • Ivan:

    Особенно приятно, что можно оставлять комментарии без регистрации.

    ЭТО ПРОСТО ОГОНЬ

  • ввв:

    спасибо огромное вам!

  • Junior Dev:

    Друг, очень круто и все понятно! Молодец!

  • Fairuza:

    ругается на эту строку

    Cannot read properties of null (reading ‘addEventListener’)

    hamb.addEventListener(«click», hambHandler);

      

  • мечехвост:

    текст под меню помещается следом идущий, нужно еще прописать в коде, чтоб последующие блоки начинались далее

  • Андрей:

    Огромное спасибо!

    Прекрасная статья, отличное изложение, лаконичная и чёткая вёрстка.

    Автору — респект и удачи.