Если без гамбургерного меню не обойтись, то начать стоит с выделения меню в отдельный контейнер и добавления кнопки‑тригера. Покажу на примере типового меню «в строку»:
<header class="header">
<div class="logo">
<a href="/">
<img src="logo.svg" width="40" height="40">
</a>
</div>
<nav class="nav">
<ul>
<li class="nav__item">
<a href="/products/">Продукция</a>
</li>
<li class="nav__item">
<a href="/services/">Услуги</a>
</li>
<li class="nav__item is__active">
<a href="/blog/">Блог</a>
</li>
<li class="nav__item">
<a href="/contacts/">Контакты</a>
</li>
</ul>
</nav>
<!-- aria-label подскажет смысл кнопки программам чтения с экрана -->
<button class="hamburger" type="button" aria-label="Открыть меню">
<span class="hamburger-box">
<span class="hamburger-inner"></span>
</span>
</button>
</header>
Стилизуем кнопку. Возьмём уже готовые стили из библиотеки «гамбургерных» иконок на ЦСС:
<link rel="stylesheet" src="styles/hamburgers.css"></link>
<!-- ... -->
<header class="header">
<div class="logo">
<!-- ... -->
</div>
<nav class="nav">
<!-- ... -->
</nav>
<button class="hamburger hamburger--squeeze" type="button">
<!-- ... -->
</button>
</header>
.header .hamburger {
color: inherit; /* Чтобы иконка унаследовала цвет текста, а не была белой */
line-height: 0; /* Чтобы иконка не увеличивала высоту меню */
}
Научим кнопку «кликаться». Пускай пока она меняет своё состояние и добавляет или убирает класс у меню:
<script>
document
.querySelectorAll('.hamburger')
.forEach(button => {
const nav = button
.closest('.header')
.querySelector('.nav')
button.addEventListener('click', () => {
button
.classList
.toggle('is-active')
nav
.classList
.toggle('is-active')
})
})
</script>
Скроем кнопку на достаточно широких экранах. А на узких экранах разложим меню вертикально:
@media (width > 500px) {
.header .hamburger {
display: none;
}
}
@media (width <= 500px) {
.header {
position: relative; /* Задаём контекст для позиционирования меню */
grid-template-columns: min-content 1fr;
}
.nav {
position: absolute; /* Меню позиционируем абсолютно, сразу после шапки поверх содержимого */
top: 0;
left: 0;
width: 100%; /* Растягиваем меню на всю ширину экрана */
padding: 92px 10px 20px; /* Добавляем настолько большой верхний падинг, чтобы меню встало точно под шапкой */
margin: 0;
}
.nav ul {
grid-auto-flow: row; /* Раскладываем меню рядами */
grid-auto-rows: max-content;
row-gap: 5px;
}
.nav__item a {
padding: 0;
}
}
Подключим меню к кнопке и добавим анимацию. Пусть меню приезжает сверху:
@media (width <= 500px) {
.nav {
position: absolute;
transform: translateY(-100%); /* Прячем меню за верхнюю границу экрана */
/* ... */
transition: transform 75ms ease; /* Анимируем изменение позиции меню, синхронизировав с анимацией кнопки */
transition-delay: 120ms;
transition-timing-function: cubic-bezier(.215,.61,.355,1);
}
.nav.is-active {
transform: translateY(0); /* Когда меню активно, ставим его под шапку */
}
}
Появилась проблема с наползанием. Выезжающее меню перекрывает логотип. Поправим это, добавив слой, разделяющий выезжающее меню и логотип с кнопкой:
@media (width <= 500px) {
.nav {
/* ... */
z-index: 1; /* Меню поедет на самом нижнем уровне */
transform: translateY(calc(82px - 100%)); /* Спрячем меню под слой-разделитель */
}
.header::before {
content: '';
background: inherit;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 2; /* Слой-разделитель скроет меню, пока оно проезжает под шапкой */
}
.header .logo,
.header .hamburger {
position: relative;
z-index: 3; /* Логотип и кнопка встанут на самом верху */
}
}
P. S. Это был совет о веб‑разработке. Хотите знать всё о коде, тестах, фронтенд‑разработке, цеэсэсе, яваскрипте, рельсах и джейде? Присылайте вопросы.