каталог личных
объявлений

antivan. Дом проектов

Web-разработка. Бургер-меню

Задача - меню для сайта, которое будет превращаться в “бургер” при уменьшении размера экрана (на мобильных устройствах, например), а этот “бургер” будет превращаться в обратно в меню по необходимости.

Надо? Разбираемся!

Вариант 1

Это самое начало. Тут будет только “бургер”-меню на базе CSS.

Можно скачать файлы и распаковать, а можно создать их, скопировав из текста ниже.

index.html:

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Бургер-меню</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>

  <nav class="nav">
    <input type="checkbox" id="menu-toggle" class="menu-toggle">
    <label for="menu-toggle" class="menu-icon">&#9776;</label>

    <ul class="menu">
      <li><a href="#">Главная</a></li>
      <li><a href="#">О нас</a></li>
      <li><a href="#">Услуги</a></li>
      <li><a href="#">Контакты</a></li>
    </ul>
  </nav>
</body>
</html>

style.css:

body { /* для всего документа, для нашего примера эти параметры не принципиальны */
  margin: 0; /* отключаем отступы от краев (внешние отступы) */
  font-family: sans-serif; /* определяем шрифт без засечек */
}

.nav {
  background-color: #333;
  padding: 10px 20px; /* в навигационном блоки задаем внутренние отступы сверху-снизу и слева-справа */
}

.menu-icon { /* это стиль для единственного значка, собственно, "бургера" */
  font-size: 26px;
  color: white;
  cursor: pointer; /* превращаем курсор в "пальчик" для нажатия на ссылку */
  /* display: inline-block;  указываем, что наш "бургер" просто символ, но оставляем за собой право поработать с ним, как с блоком. в нашем случае, кажется, значения не имеет */
}

.menu-toggle {
  display: none; /* скрываем чекбокс */
}

.menu {
  display: none; /* указываем, что объект с этим стилем просто не отображается */
  list-style: none; /* задаем стиль списка, в нашем случае, просто отключаем маркеры */
  margin: 0; /* внешние отступы */
  padding: 0; /* внутренние отступы */
/*  flex-direction: column; */
  background-color: #444;
  position: absolute; /* указываем абсолютные координаты для блока меню */
  top: 50px; /* сверху отступаем (подбираем экспериментально) */
  left: 0px; /* слева не отступаем, т.к. меню на всю ширину - ни к чему */
  width: 100%; /* если это свойство совсем убрать, ширина выпадающего меню будет равна самому широкому элементу. Если делаем так, то и отступ слева можно задать */
}

.menu li a {
  display: block; /* тут указываем, что ссылка в меню, она же - элемент меню, будет на всю ширину */
  padding: 12px 20px; /* внутренние отступы */
  color: white;
  text-decoration: none;
  border-top: 1px solid #555;
}

.menu li a:hover { /* немного меняем фон под текстом в меню при наведении */
  background-color: #555;
}

/* Показываем меню, если чекбокс включён */
.menu-toggle:checked + .menu-icon + .menu {
  display: inline;
}

Что тут происходит?

Отображается блок nav, в нем блок ввода checkbox, потом label, содержащий один символ - “бургер”. Следом идет собственно, меню.

Стиль .nav определяет, как будет отображаться блок nav и содержимое. Стиль .menu-toggle определяет, что чекбокс не будет отрисован браузером. label через id=“menu-toggle” и for=“menu-toggle” отрисовываем “бургер” или любой другой символ, и связываем этот символ с чекбоксом, подразумевая, что нажимая на этот символ, мы щелкаем по чекбоксу. Стиль .menu определяет, что наше меню - невидимое. Это все.

Часть, где происходит магия, это:

.menu-toggle:checked + .menu-icon + .menu {
  display: inline;
}

Клик по трем черточкам “бургер”-иконки меняет статус чекбокса и CSS-селектора .menu-toggle:checked, код выше обрабатывается так - если селектор взведен, следом идет блок .menu-icon, а следом блок .menu, то вносим изменения в стиль .menu, а конкретно display: none меняем на display: inline и меню становится видимым.

Тут нужно оговориться, что ID с названием menu-toggle и CSS-стиль с названием .menu-toggle - это разные сущности, и могут называться по разному, но вот повелось так, что они называются одинаково.

Открываем в браузере index.html и видим наше меню:

меню

По клику на “бургер” получаем меню:

меню

Казалось бы, на этом можно остановиться, но тут есть недостаток: меню закрывается только при клике на “бургер”, что неудобно.

Вариант 2

Можно скачать оба файла с примером.

В index.html меняем блок nav

<nav class="nav">
  <input type="checkbox" id="menu-toggle" class="menu-toggle">
  <label for="menu-toggle" class="menu-icon">
    &#9776;
    <ul class="menu">
      <li><a href="#">Главная</a></li>
      <li><a href="#">О нас</a></li>
      <li><a href="#">Услуги</a></li>
      <li><a href="#">Контакты</a></li>
    </ul>
  </label>
</nav>

Получается, что список, непосредственно меню, теперь находится “внутри” label, наследуя его свойства.

Это совершенно не обязательно, но для понимания того, как оно еще может быть отрисовано, в style.css меняем блок .menu:

.menu {
  display: none;
  list-style: none;
  margin: 0;
  padding: 0;
  background-color: #444;
  position: absolute;
  top: 50px;
  left: 10px;
}

“Магию” тоже меняем:

.menu-toggle:checked + .menu-icon .menu {
  display: block;
}

меню

Проблему не решили. Просто попробовали еще вариант.

Вариант 3

Все также можно скачать теперь уже три файла с примером.

Упрощаем HTML и CSS, но добавляем JavaScript.

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Бургер-меню</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>

<nav class="nav">
  <div class="menu-icon" id="burger">
    &#9776;
  </div>

  <ul class="menu" id="menu">
    <li><a href="#">Главная</a></li>
    <li><a href="#">О нас</a></li>
    <li><a href="#">Услуги</a></li>
    <li><a href="#">Контакты</a></li>
  </ul>
</nav>

<script src="myScript.JavaScript"></script>

</body>
</html>

Тот же блок nav, в нем значек “бургер” и меню, с присвоенными этим блокам ID. Подключили файл с кодом JavaScript.

body {
  margin: 0;
  font-family: sans-serif;
}

.nav {
  background-color: #333;
  padding: 10px;
}

.menu-icon {
  font-size: 26px;
  color: white;
  cursor: pointer;
}

.menu {
  display: none;
  list-style: none;
  margin: 0;
  padding: 0;
  background-color: #444;
  position: absolute;
  top: 50px;
  left: 10px;
  width: 150px; /* фиксирует шириру выпадающего меню, если убрать, ширина меню установится по размеру самого широкого элемента */
}

.menu li a {
  display: block;
  padding: 12px 20px;
  color: white;
  text-decoration: none;
  border-top: 1px solid #555;
}

.menu li a:hover {
  background-color: #555;
}

.menu.active {
  display: inline;
}

В этом CSS задаются стили для всех наших блоков. Появился “вложенный” стиль .menu.active, по содержимому очень похожий на “магию” из предыдущих примеров. Он будет использоваться в JS.

  const burger = document.getElementById('burger');
  const menu = document.getElementById('menu');

  burger.addEventListener('click', () => {
    menu.classList.toggle('active');
  });

  // Опционально: закрытие меню при клике вне
document.addEventListener('click', (e) => {
  if (!burger.contains(e.target) && !menu.contains(e.target)) {
    menu.classList.remove('active');
  }
});

Этим скриптом мы навешивам не страницу 2 ждуна кликов на странице: 1. Если кликаем на “бургер”, то производим переключение стиля .menu на .menu.active или обратно, 2. если кликаем мимо “бургера” или меню, удаляем из стиля .active.

Вариант 4

Скачать демонстрационные файлы.

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Бургер-меню</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <nav>
        <div class="logo">Мое меню</div><!-- это элемент необязателен, но если его убрать, верстка меню в десктоп-режиме расползется, нужно будет бургер прижать вправо -->
        <div id="burger" class="burger"><!-- &#9776; --><!-- можно не рисовать бургер через CSS, а оставить символ -->
            <span class="burger-line"></span>
            <span class="burger-line"></span>
            <span class="burger-line"></span>
        </div>
        <ul id="menu" class="menu">
            <li><a href="#">Главная</a></li>
            <li><a href="#">О нас</a></li>
            <li><a href="#">Услуги</a></li>
            <li><a href="#">Контакты</a></li>
        </ul>
    </nav>
    

    <script src="myScript.JavaScript"></script>
</body>
</html>
body {
    margin: 0;
    font-family: sans-serif;
}

nav {
    background-color: #444;
    padding: 10px 20px;
/* включаем flexbox для навигационной панели.
по-умолчанию это будет означать, что все элементы,
которые мы разместим тут, будут
располагаться слева направо друг за другом */
    display: flex;
/* в строке меню у нас будет 2 элемента: заголовок и меню.
следующие 2 строки прижимают эти блоки к краям по горизонтали
и центрируют по вертикали*/
    justify-content: space-between;
    align-items: center;
}

.logo { /* если убираем лого из HTML (не озаглавливаем меню), то и этот класс можно убрать */
    color: #fff;
    font-size: 24px;
}

.menu {
    list-style: none;
/* меню у нас тоже располагается горизонтально */
    display: flex;
}

.menu li {
/* последовательные элементы в flexbox режиме
прижимаются друг к другу. задаем отступы */
    margin-left: 20px;
}

.menu a {
    color: #fff;
    text-decoration: none;
    font-size: 18px;
}

.menu li a:hover {
  color: #555;
}

.burger {
    display: none;
    flex-direction: column;
    justify-content: space-around;
    width: 30px;
    height: 25px;
    cursor: pointer;
}

.burger-line { /* для рисования "бургера" через CSS */
    width: 30px;
    height: 5px;
    background-color: #fff;
    border-radius: 5px;
}

@media (max-width: 530px) {
    .menu {
        display: none;
        padding: 0px;
        background-color: #444;
        position: absolute;
        top: 20px;
        left: 0px;
        width: 100%;
/*        border-radius: 5px; */
    }

    .menu li a {
      display: block;
      padding: 12px 20px;
      color: white;
      text-decoration: none;
      border-top: 1px solid #555;
    }

    .burger {
        display: flex;
    }

    .menu.active {
        display: block;
    }
}
const burger = document.getElementById('burger');
const menu = document.getElementById('menu');

burger.addEventListener('click', () => {
menu.classList.toggle('active');
});

// Опционально: закрытие меню при клике вне
document.addEventListener('click', (e) => {
  if (!burger.contains(e.target) && !menu.contains(e.target)) {
    menu.classList.remove('active');
  }
});

JS тут вообще без изменений, HTML без существенных изменений. Интересное происходит в CSS.
При открытии на десктопе (широкое окно) мы отрисовываем горизонтальную линию меню (используем FlexBox). Никаких выпадающих меню не нужно, JS не задействуется.

меню без бургера, широкое окно

Если мы уменьшаем ширину окна до 530px и/или меньше или сразу открываем страницу на мобильном устройстве, “подгружаются” стили из блока @media (max-width: 530px), подменяя собой те, что были объявлены ранее. “Бургер” мы отрисовываем, а меню прячем, меняя его свойства.

меню с бургером при узком окне

Когда происходит клик по бургеру, отрисовывается меню в новом стиле, уже горизонтальное и на весь экран мобильного устройства. Закрывается меню по клику по бургеру и мимо бургера и меню.

меню с бургером при узком окне

Закончили.

Можете сказать спасибо.
Оно мне очень пригодится.