Создаем лендинг сайт с нуля: анимированное burger меню #12
Привет! Сегодня сделаем мобильное анимированное меню для нашего лендинга, применим библиотеку framer-motion (motion) для красивого эффекта открытия. Будет интересно, погнали!
Полезные ссылки:
- Шаблон лендинга, который мы будем делать, доступен в Figma по ссылке.
- Код данного урока доступен в репозитории GitHub по ссылке.
- Подписывайтесь на мой Дзен канал
Устанавливаем пакет hamburger-react
Чтобы не писать лишний код анимации, можно воспользоваться пакетом hamburger-react, который предоставляет нам анимированное меню с обработчиком закрытия, отслеживанием состояния и небольшой кастомизацией в виде указания цвета и размера иконки.
Стиль анимации выбирается при импорте модуля, в нашем случае это squash.
Для установки в консоль вводим команду.
npm i hamburger-react
Создаем компонент MobileMenu.jsx
Создадим блок мобильного меню, для этого в папке /app/components/blocks/ создаем файл MobileMenu.jsx.
Содержимое файла MobileMenu.jsx
import Link from 'next/link';
import { motion } from 'motion/react';
export default function MobileMenu({ close }) {
return (
<motion.div
initial={{ opacity: 0, scale: 0 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0, transition: { duration: 0.2 } }}
transition={{ duration: 0.3 }}
className='absolute inset-0 bg-secondary text-on-secondary z-40'
>
<div className='flex flex-col items-center gap-10 pt-40 pb-10 px-10 text-2xl font-bold uppercase'>
<Link href={'#products'} onClick={() => close()}>
Наша продукция
</Link>
<Link href={'#about'} onClick={() => close()}>
О нас
</Link>
<Link href={'#contacts'} onClick={() => close()}>
Контакты
</Link>
</div>
</motion.div>
);
}
Это обычный блок верстки с абсолютным позиционированием, перекрывающий всё окно.
Для того чтобы была возможность использовать кнопку меню для закрытия, я добавил z-index в это меню, а также в контейнер значка мобильного меню.
Чтобы анимация motion работала, я воспользовался стандартной конструкцией этой библиотеки — создал блок motion.div и в качестве атрибутов установил значения для стартового значения анимации, итогового и завершающего, в данном случае анимируются значения масштаба и прозрачности.
Обработчик события onClick необходим для закрытия меню при клике по нему, а также для удаления стиля style="overflow: hidden;" с корневого контейнера. Добавлять данный стиль мы будем в компоненте Header.jsx.
Это необходимо для того, чтобы при скролле на открытом меню страница не прокручивалась.
Рефакторинг блока Header.jsx Содержимое файла Header.jsx
'use client';
import { useState, useEffect } from 'react';
import Link from 'next/link';
import Logo from '../elements/Logo';
import SocialIcons from './SocialIcons';
import { Squash as Hamburger } from 'hamburger-react';
import MobileMenu from './MobileMenu';
import { AnimatePresence } from 'motion/react';
export default function Header() {
const [isOpen, setIsOpen] = useState(false);
const menuToggleHandler = () => setIsOpen(!isOpen);
const menuCloseHandler = () => setIsOpen(false);
useEffect(() => {
if (isOpen) document.documentElement.style.overflow = 'hidden';
return () => {
document.documentElement.style.overflow = '';
};
}, [isOpen]);
return (
<>
<header className='flex justify-between lg:h-20 mt-7'>
<div className='flex grow flex-col lg:flex-row lg:justify-between lg:items-center gap-2'>
<Logo href={'/'} />
<div className='flex flex-col lg:flex-row lg:justify-between lg:items-center gap-2 lg:gap-12'>
<nav className='hidden lg:block'>
<ul className='flex gap-12 font-light'>
<li>
<Link href={'#products'}>Наша продукция</Link>
</li>
<li>
<Link href={'#about'}>О нас</Link>
</li>
<li>
<Link href={'#contacts'}>Контакты</Link>
</li>
</ul>
</nav>
<span className='font-black'>+7 999 888 88 88</span>
<SocialIcons />
</div>
</div>
<div className='block lg:hidden z-50'>
<Hamburger toggled={isOpen} size={36} toggle={menuToggleHandler} color='hsl(var(--color-background))' />
</div>
</header>
<AnimatePresence>{isOpen && <MobileMenu close={menuCloseHandler} />}</AnimatePresence>
</>
);
}
Импортируем компонент Hamburger, который будет значком меню нашего лендинга в мобильном разрешении, и задаём ему необходимые параметры.
Для работы нам необходимо хранить состояние открытия меню — isOpen, а также два обработчика — переключатель открытия меню и закрытие меню.
Можно было обойтись только переключателем, но для надёжности при клике на пункте меню я предпочитаю именно закрывать его.
Хук useEffect необходим для установки style="overflow: hidden;" страницы, чтобы предотвратить скроллинг при открытом меню.
Конструкция
<AnimatePresence>...</AnimatePresence>
Необходима для отображения анимации компонента как при открытии, так и при закрытии, без этого при закрытии меню будет резко исчезать.
В dev-режиме, мы получим вот такой блок нашего сайта:
В следующих статьях займемся анимациями секций при скролле страницы.
Шаблон лендинга, который мы будем делать, доступен в Figma по ссылке.
Код данного урока доступен в репозитории GitHub по ссылке.
На этом всё, добавляйте сайт в избранное, чтобы не пропустить новых статей, а также подписывайтесь на мой Дзен-канал – dzen.ru/in9var