Гид по технологиям

Как создать переключаемое мобильное меню на чистом HTML/CSS/JS

3 min read Frontend Обновлено 30 Dec 2025
Переключаемое мобильное меню на чистом HTML/CSS/JS
Переключаемое мобильное меню на чистом HTML/CSS/JS

Скриншот структуры HTML-документа

Важно: этот подход даёт полный контроль над разметкой и стилем. Вы можете подключать Tailwind или Bootstrap позже, но знание базовой реализации полезно для отладки и кастомизации.

Как создать переключаемое мобильное меню

Откройте папку проекта и создайте три файла: index.html, styles.css, script.js. Ниже — пример минимальной разметки, стилей и скрипта.

HTML:




    Mobile Navigation Menu
    


    

CSS:

/* Этот блок для примера — подгоняйте под свой дизайн */
section{
    width: 800px;
    height: 600px;
    margin-top: 50px;
    margin-left: 250px;
    border: solid black 1px;
    background: #e6e3dc;
}

/* Позиционируем контейнер значка меню */
#toggle-container{
    display: grid;
    width: fit-content;
    margin-left: 720px;
    margin-top: 10px;
    gap: 5px;
    cursor: pointer;
}

/* С Stack из трёх полосок: задаём размер и цвет */
#one, #two, #three{
    background: black;
    width: 30px;
    height: 3px;
}

.toggle-content{
    display: none;
    margin-left: 700px;
    margin-top: 20px;
}

.toggle-content a{
    display: block;
    text-decoration: none;
    color: black;
    font-size: 30px;
}

.toggle-content a:hover{
    color: blue;
}

/* Класс, который показывает меню */
.displayed{
    display: block;
}

JavaScript (минимальный, переключение при клике):

var toggler = document.getElementById("toggle-container");
var toggleContents = document.getElementById("toggle-content");

// Переключаем класс, который управляет видимостью
toggler.addEventListener("click", function(event){
    // переключаем состояние видимости
    toggleContents.classList.toggle("displayed");
    // обновляем aria-* для доступности
    var expanded = toggler.getAttribute('aria-expanded') === 'true';
    toggler.setAttribute('aria-expanded', String(!expanded));
    toggleContents.setAttribute('aria-hidden', String(expanded));
});

// Клавиатурная поддержка: Enter и Space
toggler.addEventListener('keydown', function(e){
    if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        toggler.click();
    }
});

Работающий пример переключаемого мобильного меню

Выше реализовано простое переключение: клик по значку меняет класс displayed у блока .toggle-content, и меню показывается или скрывается.

Важно: исходный пример в статье имел две распространённые ошибки — неконсистентное имя класса (display vs displayed) и обработчик, который закрывал меню не надёжно. Ниже — исправления и улучшения.

Закрытие меню при клике вне элемента (надежный вариант)

Если вы хотите, чтобы меню закрывалось при клике в любое место вне меню, используйте делегирование и проверку целевого элемента. Ниже — надёжный вариант:

// Закрывать меню при клике вне toggle-container
window.addEventListener('click', function(event){
    var isClickInside = toggler.contains(event.target);
    if (!isClickInside){
        // если меню открыто — закрываем
        if (toggleContents.classList.contains('displayed')){
            toggleContents.classList.remove('displayed');
            toggler.setAttribute('aria-expanded', 'false');
            toggleContents.setAttribute('aria-hidden', 'true');
        }
    }
});

Примечание: если у вас есть вложенные контролы в меню (кнопки, формы), проверка через .contains() корректно учитывает клики внутри.

Доступность и UX улучшения

  • Добавьте role=”button”, tabindex=”0” и aria-expanded/aria-controls, как в примере HTML.
  • Обеспечьте клавиатурную навигацию: Enter и пробел должны переключать меню.
  • При сложных меню рассмотрите управление фокусом (focus trap) и возврат фокуса к источнику при закрытии.

Исправление распространённых ошибок

Факт: часто встречаются две ошибки:

  1. Проверка и удаление класса ищет “display”, тогда как JavaScript добавляет “displayed”. Это приводит к тому, что меню не закрывается корректно.
  2. Обработчик клика навешан на document без проверки, что клик был вне меню — это может вызывать непредсказуемое поведение.

Исправление: используйте согласованное имя класса (displayed), проверяйте event.target с помощью .contains(), и обновляйте aria-атрибуты.

Мини‑методология: быстрый чек-лист перед публикацией

  • Меню работает при клике по иконке
  • Меню закрывается при клике вне элемента
  • Клавиатурная навигация: Enter / Space
  • aria-expanded и aria-hidden выставляются корректно
  • Нет конфликтов имён классов
  • Стиль меню адаптирован под экран < 768px

Критерии приёмки

  1. При клике на иконку меню появляется список навигации.
  2. Повторный клик скрывает список.
  3. Клик вне меню скрывает меню, если оно открыто.
  4. Управление работает клавиатурой (Enter/Space).
  5. aria-expanded меняется при каждом переключении.

Когда этот подход не сработает

  • На очень сложных сайтах с несколькими слоями оверлеев стоит использовать focus trap и блокировку скролла.
  • Если требуются анимации на уровне производительности (много элементов одновременно), нужна оптимизация CSS-анимаций или использование requestAnimationFrame.
  • Для мультиязычных интерфейсов с динамическим контентом потребуется дополнительная логика для управления фокусом и ориентацией.

Альтернативные подходы

  • Использовать CSS-only решение через input[type=”checkbox”] + :checked для простых меню (без JavaScript).
  • Подключать готовые компоненты из UI-библиотек (если важна скорость разработки).
  • Использовать библиотеку управления фокусом (focus-trap) для сложных модальных меню.

Примеры улучшений (идеи)

  • Анимация: плавное появление меню через transform и opacity.
  • Тёмная/светлая тема для меню.
  • Иконка гамбургера превращается в крестик при открытии (анимация полосок).
  • Тесты: добавить E2E тест, проверяющий открытие/закрытие меню и поведение при клике вне.

Итог

Вы реализовали простое переключаемое мобильное меню без фреймворков. Такой подход даёт гибкость и точный контроль над доступностью и поведением. Для продакшн‑варианта добавьте обработку клавиатуры, проверку кликов вне элемента и мелкие визуальные улучшения.

Важно: всегда тестируйте на устройствах с тач‑управлением и с клавиатурной навигацией.

Краткие выводы:

  • Простая реализация — три div + скрытый блок навигации.
  • Управление видимостью — класс CSS, переключаемый JavaScript.
  • Улучшения: aria-атрибуты, закрытие по клику вне, клавиатурная поддержка.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Сброс Sonos до заводских настроек — инструкция
Руководство

Сброс Sonos до заводских настроек — инструкция

Django CBV: CRUD менеджер задач
Django

Django CBV: CRUD менеджер задач

Миниатюра YouTube в Canva — быстрый гид
Дизайн

Миниатюра YouTube в Canva — быстрый гид

Как сэкономить мобильные данные на iPhone
iPhone

Как сэкономить мобильные данные на iPhone

Музыка на нескольких Google Nest — группа динамиков
Smart Home

Музыка на нескольких Google Nest — группа динамиков

Как сделать «тупой» телевизор умнее
Гаджеты

Как сделать «тупой» телевизор умнее