Готовим бургер меню на CSS, HTML и JQuery

Приправим этот день приятным вкусом гамбургера! Как известно, верстальщики — это особый тип гурманов, который увлеченно прячет вкусняшки в разных частях сверстанной страницы, например, в меню. Вы только посмотрите, как постарался верстальщик, упаковавший такой длинный список пунктов меню в маленький трехэтажный гамбургер. Еще и добавил анимационный спецэффект: начинка из гамбургера высыпается с небольшой задержкой, так что нижний и верхний слои бургера успевают наклониться и образовать крестик!

Предлагаю закодить этот фокус в своем текстовом редакторе! И первым шагом на пути к бургеру будет техническое задание:

Техническое задание:

У нас имеются готовые html и css файлы со стандартным горизонтальным меню в шапке сайта и отличным юзабилити для просмотра страницы на широком экране. В настоящий момент меню выглядит следующим образом:

Текущий HTML-файл:

<!DOCTYPE HTML>
<html>
<head>
</head>
    <title>Меню-гамбургер</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="style.css" type="text/css">
    <link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
</head>
<body>
<header class = "header">
    <div class="container header__container">
        <div class="menu-burger__header">
            <span></span>
        </div>
        <nav class="header__nav">
            <ul class="menu header__menu">
                <li><a href="" class="menu__item">Главная</a></li>
                <li><a href="" class="menu__item">Товары</a></li>
                <li><a href="" class="menu__item">Акции</a></li>
                <li><a href="" class="menu__item">Новинки</a></li>
                <li><a href="" class="menu__item">Доставка</a></li>
                <li><a href="" class="menu__item">Контакты</a></li>
            </ul>
        </nav>
    </div>
</header>
<div class="content-wrapper">
    <div class = "container content-wrapper__container">
        <p>
            Кракозябры на сайте — это не что иное, как неверная интерпретация браузером информации, сохраненной в Вашем файле. В двух словах опишу суть процесса: прежде чем сохранить, к примеру, html-файл, компьютер с помощью кодировочных таблиц переводит каждый символ на свой «компьютерный язык», который состоит из единиц и нулей. И только после этого тщательно сохраняет полученные последовательности ноликов и единичек в ячейках памяти. Когда мы открываем файл в браузере, браузер также «достает из широких штанин» кодировочные таблицы и переводит каждый символ обратно с компьютерного языка на человеческий. И если кодировочные таблицы, в соответствии с которыми браузер отображает символы при открытии файла, отличаются от кодировочных таблиц, которые использовались при сохранении файла, появляются кракозябры.
        </p>        
    </div>    
</div>
</body>
</html>

Текущий CSS-файл:

* {
    margin: 0;
    padding: 0;
    border: 0;
    box-sizing: border-box;
}
body {
    background: #fff;
    color: #313131;
    min-height: 100vh;
    font-family: 'Roboto', Helvetica;
    font-size: 18px;
}
a {
    color: #242e31;
    text-decoration: none;
    font-weight: 600;
   }
header {
    position: fixed;
    width: 100%;
    top: 0;
    left: 0;
    z-index: 20;
    height:80px;
    background: #fff;
    box-shadow: 0 2px 5px 0 rgba(0,0,0,.1);
    display: flex;
    padding: 5px 0;
    align-items: center;
    justify-content: space-between;
}
.container{
    width: 100%;
    max-width: 1180px;
    margin: 0 auto;
    padding: 10px;
    position: relative;
}
.content-wrapper{
    width: 100%;
}
.header__nav {
    position: absolute;
    right: 36px;
    display: block;
}
.header__menu {
    display: flex;
    position: relative;
    z-index: 2;
}
.header__menu li {
    list-style: none;
    margin: 0px 0px 0px 36px;
    font-size: 16px;
    text-transform: uppercase;
    text-decoration: none;
}
.content-wrapper{
    margin-top: 78px;
    padding: 10px;
    line-height: 34px;
}

Шапочка выглядит пустовато: я не стала размещать логотип и другие элементы, чтобы не отвлекаться от работы с меню. Несмотря на это, при сужении экрана пункты меню наползают друг на друга и шапка превращается в хаос. Поэтому нужно для экранов мобильных устройств, то есть для таких гаджетов, у которых ширина менее 768px:

1. Приготовить аппетитный бургер и расположить его в верхней левой части экрана. Бургер должен выглядеть как на изображении ниже:

2. Создать скрипт, реагирующий на клик мыши по иконке бургера. При клике левой кнопки мыши, средний слой должен плавно исчезать, а верхний и нижний слои — менять углы наклона и образовывать крестик.

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

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

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

Инструменты: HTML, CSS, JQuery

1. Рисуем бургер меню в левом верхнем углу шапки

В соотсветствии с html-структурой, для бургер-меню у нас заготовлен блок с классом «menu-burger__header»:

             . . .       
<div class="menu-burger__header">
    <span></span>
</div>
            . . .

Над этим блоком мы и поколдуем!

Так как потребность в бургере порождена желанием адаптировать меню к мобильным устройствам, то css-стили для узких экранов шириной менее 768px мы будем записывать внутри медиазапроса: @media(max-width: 767px){ … }

Откроем css-файл и в самом конце файла разместим медиазапрос: «@media(max-width: 767px){ }» Между скобками медиазапроса расположим стили для класса «menu-burger__header»:

@media(max-width: 767px){
    .menu-burger__header {
        position: relative; /* задаем относительное позиционирование */
        width: 40px; /* определяем размеры блока */
        height: 35px;
        display: block;
        margin-left: 10px;
    }
}

В нашем бургере будет 3 слоя. Средний слой практически готов: его образует пара тегов <span></span>, размещенных в блоке <div class=»menu-burger__header»></div>. Осталось лишь определить размеры слоя и окрасить его, дабы он стал видимым для пользователей. Верхний и нижний слои мы создадим посредством псевдоэлементов :before и :after. В моем бургере все 3 слоя будут одинаковы на вид, отличать их будет лишь занимаемая позиция. Поэтому я задам общие для этих слоев стили для прорисовки слоев, а ниже добавлю позиционирующие стили для каждого слоя отдельно:

.menu-burger__header span, .menu-burger__header:after, .menu-burger__header:before{
    height: 3px;
    width: 100%;
    position: absolute;
    background: #515758;
    margin: 0 auto;
}
.menu-burger__header span{
    top: 21px;
}
.menu-burger__header:after, .menu-burger__header:before{
    content: '';
}
.menu-burger__header:after{
    bottom: 5px;
}
.menu-burger__header:before{
    top: 5px;
}

После этого можно сохранить стили и обновить страницу — бургер создан!

Дополнительно для мобильной версии я уменьшила высоту шапки и немного сдвинула вверх контентную часть:

header {
    height: 60px;
}
.content-wrapper {
    margin-top: 48px;
}

В результате меню приобрело следующий вид:

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

.header__nav {
    display: none;
}

Теперь я довольна результатом и предлагаю двигаться дальше:

2. Пишем скрипт анимации бургера при клике мыши.

Пришло время подключить тяжелую артиллерию, а именно: JQuery! Для этого перед закрывающим тегом </body> в html-файле я добавила строку:

<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>

А ниже подключим файл script.js, который расположим в папке «js»:

<script src="js/menu.js"></script> 

Библиотека подключена, js-файл создан, пришло время покодить в файле «menu.js»! Первым делом посредством метода click() привяжем обработчик событий click к нажатию на иконку бургера. Если нажатие произошло, то добавим к блоку с меню дополнительный класс ‘open-menu’:

$(document).ready(function() {
    $('.menu-burger__header').click(function() {
        $('.menu-burger__header').toggleClass('open-menu');
    });
});

Осталось лишь прописать изменения в стилях. Я предлагаю наколдовать плавное исчезновение среднего слоя бургера и одновременные повороты верхнего и нижнего слоев до образования крестика:

.menu-burger__header.open-menu span {
    opacity:0; 
    transition: 0.5s; 
}
.menu-burger__header.open-menu:before {
    transform: rotate(38deg);
    top: 16px;
    transition: 0.4s;
}
.menu-burger__header.open-menu:after {
    transform: rotate(-38deg);
    bottom: 16px;
    transition: 0.4s;
}

Анимация бургера удалась на славу! А это значит, что мы переходим к следующему пункту ТЗ:

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

В конце 1 пункта статьи мы приняли временную меру — скрыли горизонтальное меню свойством display: none

.header__nav {
     display: none;
 }

Давайте вернем горизонтальное меню в область видимости, заменив значение «none» на «block»:

.header__nav {
    display: block;
} 

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

.header__nav {
    display: block;
    position: absolute;
    top: 55px;
    left: 0;
    background: rgb(245, 246, 246);
    box-shadow: #ccc;
    width: 100%;
    box-shadow: 0 4px 2px -2px rgba(36, 36, 36, 0.17);
}

Зададим свойства селекторам «.header__menu» и «.header__menu li» для узких экранов:

.header__menu {
    display: block;
}
.header__menu li {
    margin: 40px 0px 40px 33px;
    font-size: 14px;
}

Посмотрим, что получилось:

Вертикальное меню готово! Осталось сделать анимацию так, чтобы меню выдвигалось слева при нажатии на иконку бургера!

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

Анимацию будем создавать посредством свойства transition, примененного к селектору .header__nav. Сначала мы зададим блоку с классом «header__nav» смещение влево на 100% и пропишем свойство transition со значением «all 0.4s ease» для того, чтобы изменение свойств блока с меню происходило в течение 0.4s:

.header__nav {
    display: block;
    position: absolute;
    top: 55px;
    left: 0;
    background: rgb(245, 246, 246);
    box-shadow: #ccc;
    width: 100%;
    box-shadow: 0 5px 6px rgba(36, 36, 36, 0.37);
    left: -100%;
    transition: all 0.4s ease;
}

Само изменение свойств блока будет происходить при наступлении события — клика по левой кнопки мыши. В CSS это событие будет проявляться добавлением класса «open-menu» в блок с меню рядом с классом «header__nav». Сразу запишем для селектора .header__nav.open-menu меняющееся свойство:

.header__nav.open-menu {
    left: 0;
}

Осталось привязать добавление класса «open-menu» к щелчку по левой кнопки мыши. Для этого вернемся в созданный ранее js файл и добавим строку «$(‘.header__nav’).toggleClass(‘open-menu’):»

$(document).ready(function() {
	$('.menu-burger__header').click(function(){
        $('.menu-burger__header').toggleClass('open-menu');
        $('.header__nav').toggleClass('open-menu');
	});
});

Меню готово и работает так, как и планировалось:

С техническим заданием мы справились! Однако, я предлагаю внести небольшие коррективы в наш код для улучшения юзабилити меню.

Зачистим шероховатости: добавим прокрутку в меню и уберем скроллинг основного текста на странице.

Для того, чтобы меню прокручивалось в случае, если оно не вмещается на экран мобильного устройства, добавим в селектор «.header__menu» свойство «overflow: auto»:

.header__menu {
    position: fixed;
    top: -100%;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: auto; /*для того, чтобы меню скроллилось в случае, если оно не влезает на экран*/
    background-color: #18b5a4;
    padding: 70px 10px 20px 10px;
    transition: all 0.3s ease 0s;
}

Теперь меню в случае расширения будет легко скроллиться на кротких экранах. Однако, вместе с меню будет прокручиваться и основной текст страницы, расположенный под меню. Это может привести к неожиданным эффектам. Чтобы такой ситуации не произошло, заблокируем тело страницы на весь период, пока будет открыто меню. Для этого добавим телу страницы body класс при открытом меню: $(‘body’).toggleClass(‘fixed-page’);

$(document).ready(function() {
	$('.header__burger').click(function(event){
        $('.header__burger, .header__menu').toggleClass('active');
        $('body').toggleClass('fixed-page');
	});
});

А в CSS-свойствах добавим блокировку страницы для блока с классом «fixed-page»:

.fixed-page{
    overflow: hidden; /*запрещаем прокручивание страницы при открытом меню*/
}

Ура! Все отлично работает и радует глаз верстальщика. А если и остались какие-то шероховатости, то всегда можно взять в эти руки напильник и допилить основу до нужного состояния! Всем удачи, и вкусных вам бургеров!

Финальный код

Архив с итоговыми файлами можно скачать по ссылке: burger-menu.zip. Для того, чтобы проверить работоспособность кода, нужно разархивировать скачанную папку и открыть файл menu.html в браузере. При уменьшении ширины браузера стандартное меню будет трансформироваться в бургер-меню!

7 комментариев

  1. Большое спасибо, за отличное объяснение!

    1. Автор

      Проверьте, правильно ли указан путь к файлу с js-скриптом и верно ли подключен jQuery — это строки, расположенные в конце html-файла:
      <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
      <script src="js/menu.js"></script>

      Обратите внимание, что для подключения jQuery по внешней ссылке нужен интернет!
      В конце статьи я добавила ссылку с архивом кода, чтобы можно было проверить работоспособность. Продублирую ссылку здесь: Burger-menu.zip Только после извлечения архива не меняйте расположение файлов внутри распакованной директории. Протестировала еще раз, все работает, проверяйте, пожалуйста! 🙂

    2. Всем здравствуйте. Всё работает, Спасибо за статью, за объяснения. Отдельное спасибо за исходники.
      На локальном сервере (на компе) не работает. Уменьшаю окно браузера, увеличиваю масштаб, меню сворачивается, как и должно быть, но при нажатии ничего не происходит.
      На боевом сервере, на хостинге все работает. И с компа и с телефона.
      Хочу попробовать сделать вложенность.

  2. А что делать для страниц php, если они не распознают псевдоклассы «before» и «after»?

    1. Автор

      Вы же встраиваете html-код в php страницу, поэтому все должно работать. Посмотрите в архиве по ссылке: Меню2. Там описанный в статье код сохранен в файле «header.php», который подгружается в основной файл «main.php». Подключение js-скриптов вынесено в конец файла «main.php». Протестить можно прямо на нашем сайте здесь: https://webtort.ru/works/main.php: при нажатии F12 и уменьшении ширины браузера меню превращается в бургер.

Добавить комментарий для DRA Отменить ответ