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">☰</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">
☰
<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">
☰
</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"><!-- ☰ --><!-- можно не рисовать бургер через 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), подменяя собой те, что были объявлены ранее. “Бургер” мы отрисовываем, а меню прячем, меняя его свойства.

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

Закончили.