Настройка мобильного меню на сайте

10.10.2021

Тема не новая, просто хочу вынести пример мобильного меню, который я использую чаще всего. На данный момент у каждого современного человека есть смартфон, с помощью которого из любой точки мира можно зайти на любой сайт и на данный момент (2021 год) каждый сайт должен быть адаптирован под мобильные телефоны, тем более, что сейчас в эпоху IoT даже холодильник и духовка Bosch имеют интерфейс для выхода в интернет.

Не забываем добавить параметры Viewport — это видимая пользователю область веб-страницы. Т.е. это то, что может увидеть пользователь, не прибегая к прокрутке.

<meta name="viewport" content="width=device-width, initial-scale=1.0">

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

HTML макет для меню

<header class="header" id="header">
  <div class="wrap">
    <a href="" class="logo">
      LOGO
    </a>

    <ul class="main-menu" id="main-menu">
      <li class="menu-item"><a href="">Home</a></li>
      <li class="menu-item"><a href="">About</a></li>
      <li class="menu-item"><a href="">Services</a></li>
      <li class="menu-item"><a href="">Blog</a></li>
      <li class="menu-item"><a href="">Contacts</a></li>
    </ul>

    <button class="btn-menu" id="btn-menu" type="button">
      <span class="lines"></span>
      <span class="lines"></span>
      <span class="lines"></span>
    </button>
  </div>
</header>

Простой хедер, внутри контейнера находится Логотип и Меню, для мобильного меню добавлена кнопка btn-menu.

Стили для данного меню (используется SCSS)

.header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  background-color: #fff;
  border-bottom: 1px solid #ccc;
  z-index: 10;

  .wrap {
    position: relative;
    max-width: 992px;
    margin: 0 auto;
    padding: 20px 15px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    transition: 0.4s;
  }
}

.main-menu {
  display: flex;
  align-items: center;
  justify-content: flex-start;

  .menu-item {
    margin-right: 30px;

    &:last-child {
      margin-right: 0;
    }
  }
}

.btn-menu {
  display: none;
}

Стили для красивой кнопки вызова мобильного меню.

Не обязательно делать такую кнопку, можно просто добавить иконку сендвича — будет чуть меньше кода, но вид будет примитивнее и проще. Кнопка .btn-menu скрыта по умолчанию и отображается на определённой ширине экрана.

.btn-menu {
  display: none;
  position: relative;
  width: 32px;
  height: 22px;
  background-color: transparent;
  cursor: pointer;
  border: none;
  outline: none;
  transition: 0.4s;

  .lines {
    display: block;
    width: 32px;
    height: 2px;
    border-radius: 2px;
    background-color: #000;
    position: absolute;
    transform: rotate(0deg);
    transform-origin: 50% 50%;
    transition: 0.25s ease-in-out;
    will-change: transform;

    &:nth-child(1) {
      left: 0;
      top: 0;
    }
    &:nth-child(2) {
      left: 0;
      top: 50%;
      margin-top: -1px;
    }
    &:nth-child(3) {
      left: 0;
      bottom: 0;
    }
  }

  &.active .lines {
    left: 50%;
    top: 50%;
    margin-left: -16px;
    margin-top: 0;

    &:nth-child(1) {
      transform: rotate(45deg);
    }

    &:nth-child(2) {
      width: 0;
      opacity: 0;
    }

    &:nth-child(3) {
      transform: rotate(-45deg);
    }
  }
}

Стили для мобильного вида меню

Скрываем меню, отображаем кнопку мобильного меню и задаем новые стили для активного меню:

@media (max-width: 768px) {
  .btn-menu {
    display: block;
  }
  
  .main-menu {
    display: none;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    position: absolute;
    top: 100%;
    left: 0;
    width: 100%;
    padding: 20px 0;
    background-color: #fff;

    .menu-item {
      text-align: center;
      margin: 0;
      margin-bottom: 25px;

      &:last-child {
        margin-bottom: 0;
      }
    }
  }

  .main-menu.active {
    display: flex;
  }
}

В случае, если отображение/скрытие меню активируется скриптом лучше подстраховаться, чтобы меню при изменении ширины экрана всегда отображалось на десктопе:

@media (min-width: 769px) {
  .main-menu {
    display: flex !important;
  }
}

Разбор кода javaScript

Функция checkScrolledHeader() нужна для того, чтобы кастомизировать внешний вид хедера при прокрутке, эта функция не обязательна, но она часто используется для дизайна при скроле.

(function checkScrolledHeader() {
  var $header = $("#header");

  $(window).scroll(checkScroll);

  function checkScroll() {
    if ($(window).scrollTop() > 1) {
      $header.addClass("scrolled");
    } else {
      $header.removeClass("scrolled");
    }
  }
  checkScroll();
})();

Функция initMobHeaderMenu() нужна для отображения/скрытия мобильного меню. Там всё понятно. Нажатие на кнопку меняет классы хедеру, меню и кнопке, хотя можно обойтись и одним хедером, поскольку остальные элементы являются его дочерними. Но иногда нужно вынести мобильное меню из хедера, например, чтобы разместить в нем больше элементов (соцсети, поиск, логин/авторизация), поэтому для более широких возможностей повесим классы на нужные нам элементы.

(function initMobHeaderMenu() {
  var $header = $("#header"),
      $btnMenu = $("#btn-menu"),
      $mainMenu = $("#main-menu");

  $btnMenu.on("click touchend", function (e) {
    $header.toggleClass("active");
    $(this).toggleClass("active");
    $mainMenu.toggleClass("active");
    return false;
  });
  
  // Hide menu on scroll for Landing Page
  $(window).scroll(deactivateHeader);

  function deactivateHeader() {
    $header.removeClass("active");
    $btnMenu.removeClass("active");
    $mainMenu.removeClass("active");
  }
})();

Функция deactivateHeader() нужна для скрытия открытого мобильного меню при скроле, это больше нужно для Landing Page — когда меню является навигацией по одной странице, чтобы при прокрутке к якорю меню скрывалось.

  // Hide menu on scroll for Landing Page
  $(window).scroll(deactivateHeader);

  function deactivateHeader() {
    $header.removeClass("active");
    $btnMenu.removeClass("active");
    $mainMenu.removeClass("active");
  }

Полный код можно найти ниже в примере на Codepen.

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

Чтобы увидеть как выглядит десктопная/мобильная версия меню — отключите отображение других вкладок кроме Результата:

See the Pen
Mobile Menu
by Denis (@deniscreative)
on CodePen.dark

Рекомендую к прочтению:

Оставить комментарий