Значок из трёх полосок, который скрывает навигацию, стал неотъемлемой частью современного веб-дизайна. Многие думают, что для его создания нужен JavaScript, но сегодня мы развеем этот миф и покажем, как создать полностью функциональное, адаптивное и стильное бургер-меню, используя только возможности CSS — от базовой разметки до плавных анимаций и доступности.
Что такое бургер-меню и зачем оно нужно?
Бургер-меню (или «гамбургер») — это иконка, состоящая из трёх горизонтальных линий, которая при клике или нажатии раскрывает скрытое навигационное меню. Его главная задача — экономия драгоценного пространства на экранах мобильных устройств, сохраняя при этом доступ ко всем разделам сайта. Использование чистого CSS для его реализации делает меню быстрее, проще в поддержке и независимым от выполнения скриптов в браузере пользователя.
Важно: Хотя CSS-решение элегантно, всегда проверяйте доступность (a11y). Для навигации по клавиатуре и скринридерам может потребоваться минимальная HTML-разметка с фокусом на семантике.
Шаг 1: Подготовка HTML-разметки
Всё начинается с правильной семантической структуры. Нам понадобится контейнер для кнопки и само меню.
Базовый HTML-код
<header class="header">
<!-- Кнопка-триггер -->
<button class="menu-toggle" aria-label="Открыть меню" aria-expanded="false">
<span class="menu-toggle__line"></span>
<span class="menu-toggle__line"></span>
<span class="menu-toggle__line"></span>
</button>
<!-- Само навигационное меню -->
<nav class="nav-menu">
<ul class="nav-menu__list">
<li><a href="/" class="nav-menu__link">Главная</a></li>
<li><a href="/about" class="nav-menu__link">О нас</a></li>
<li><a href="/services" class="nav-menu__link">Услуги</a></li>
<li><a href="/contact" class="nav-menu__link">Контакты</a></li>
</ul>
</nav>
</header>
Обратите внимание на атрибуты aria-label и aria-expanded. Они критически важны для пользователей скринридеров и будут управляться с помощью CSS.
Шаг 2: Магия CSS: Стилизация и логика
Вся логика работы будет построена на CSS-селекторе :checked для скрытого чекбокса или, в нашем более семантичном варианте, на псевдоклассе :focus и соседних селекторах. Мы выберем подход с использованием :focus-within для лучшей доступности.
Стилизация кнопки-бургера
.menu-toggle {
background: none;
border: none;
cursor: pointer;
padding: 15px;
z-index: 1000;
position: relative; /* Для позиционирования иконки */
}
.menu-toggle__line {
display: block;
width: 30px;
height: 3px;
background-color: #333;
margin: 6px 0;
transition: all 0.3s ease-in-out;
border-radius: 2px;
}
Скрытие меню и управление состоянием
Ключевой трюк — скрыть меню по умолчанию на мобильных устройствах и показать его при активации кнопки. Мы будем использовать соседний селектор (~) и состояние :focus кнопки.
/* Скрываем меню на мобильных по умолчанию */
@media (max-width: 768px) {
.nav-menu {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(255, 255, 255, 0.98);
transform: translateX(-100%); /* Убираем за пределы экрана */
transition: transform 0.4s cubic-bezier(0.77, 0.2, 0.05, 1.0);
padding-top: 80px;
z-index: 999;
}
.nav-menu__list {
list-style: none;
padding: 0 20px;
}
.nav-menu__link {
display: block;
padding: 15px 0;
font-size: 1.5rem;
border-bottom: 1px solid #eee;
text-decoration: none;
color: #222;
}
/* Логика открытия: когда кнопка в фокусе, меню появляется */
.menu-toggle:focus ~ .nav-menu,
.nav-menu:focus-within {
transform: translateX(0);
}
/* Анимация иконки бургера в крестик при фокусе */
.menu-toggle:focus .menu-toggle__line:nth-child(1) {
transform: rotate(45deg) translate(6px, 6px);
}
.menu-toggle:focus .menu-toggle__line:nth-child(2) {
opacity: 0;
}
.menu-toggle:focus .menu-toggle__line:nth-child(3) {
transform: rotate(-45deg) translate(8px, -8px);
}
/* Чтобы убрать стандартный outline и сделать свой */
.menu-toggle:focus {
outline: 2px dashed #4a90e2;
outline-offset: 4px;
}
}
/* На десктопах меню показываем всегда */
@media (min-width: 769px) {
.menu-toggle {
display: none; /* Прячем кнопку-бургер */
}
.nav-menu {
transform: none !important;
position: static;
height: auto;
background: none;
}
.nav-menu__list {
display: flex;
gap: 30px;
}
}
Совет по анимации: Используйте transition для свойства transform, а не left или margin. Анимация transform работает на GPU и значительно плавнее, что экономит заряд батареи на мобильных устройствах.
Шаг 3: Улучшения и нюансы
Базовый функционал готов, но есть детали, которые превращают хорошее меню в отличное.
- Закрытие по клику вне меню: На чистом CSS это сложно, но можно добавить прозрачный оверлей на всю страницу под меню, который при клике будет убирать фокус с кнопки.
- Прокрутка тела страницы: Когда меню открыто на мобильном, заблокируйте прокруту тела (
body) с помощьюoverflow: hidden. - Плавность: Поэкспериментируйте с функциями
cubic-bezierдля transition, чтобы анимация открытия felt more natural.
Альтернативный подход: Чекбокс-хаки
Классический метод — использование скрытого чекбокса (<input type=\"checkbox\" id=\"toggle\">) и селектора :checked. Он даёт больше контроля (меню остаётся открытым, пока не кликнешь снова), но менее семантичен, так как использует элемент формы не по назначению. Выбор зависит от задач проекта.
FAQ: Часто задаваемые вопросы
Можно ли сделать бургер-меню на CSS без JavaScript?
Да, абсолютно! Как мы показали в статье, с помощью псевдоклассов :focus, :focus-within или чекбокс-хака :checked можно создать полнофункциональное меню.
Как закрыть меню, кликнув на ссылку внутри него?
При использовании подхода с :focus меню закроется, как только фокус уйдёт с кнопки. Если ссылка внутри меню получает фокус (при навигации с клавиатуры), меню останется открытым благодаря :focus-within. Чтобы закрыть его после клика мышью, можно сделать ссылки блочными элементами, которые при клике уводят фокус (это поведение по умолчанию). Для чекбокс-хака нужно связать <label> с чекбоксом для каждой ссылки.
Почему мое меню не видно на десктопе?
Вероятно, медиа-запрос для десктопа (min-width) не переопределяет стили для мобильной версии. Убедитесь, что в десктопных стилях вы сбрасываете transform и position, а также отменяете display: none для контейнера меню. Используйте !important осторожно, только если другие стили имеют большую специфичность.
Как добавить тень или блюр-эффект под меню?
Используйте свойство box-shadow для контейнера .nav-menu. Для эффекта размытия фона (backdrop-filter) добавьте backdrop-filter: blur(10px); и полупрозрачный фон (background-color: rgba(255,255,255,0.8)). Учтите, что поддержка backdrop-filter не полная.
Это решение доступно (a11y)?
Базово — да, если вы используете семантический <button> и ARIA-атрибуты (aria-expanded, aria-label). Однако управление состоянием aria-expanded динамически проще всего реализовать на JavaScript. На чистом CSS можно имитировать это, меняя контент aria-label с помощью псевдоэлементов и content, но это хак. Для высоких требований к доступности небольшой JS может быть оправдан.