Бургер-меню на чистом CSS: Полное руководство без JavaScript

Бургер-меню на чистом CSS: Полное руководство без JavaScript

Значок из трёх полосок, который скрывает навигацию, стал неотъемлемой частью современного веб-дизайна. Многие думают, что для его создания нужен 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 может быть оправдан.