← Назад к вопросам

За счет чего можно открыть бургер меню?

2.0 Middle🔥 181 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

За счет чего можно открыть бургер меню

Бургер меню — это мобильное навигационное меню (три горизонтальные линии). Его можно открыть несколькими способами, каждый с разными преимуществами.

Способ 1: Нажатие на иконку (самый популярный)

Это стандартный способ — нажимаешь на иконку, меню открывается.

import { useState } from 'react';

function Header() {
  const [isMenuOpen, setIsMenuOpen] = useState(false);

  return (
    <header>
      <nav>
        {/* Иконка меню */}
        <button
          className="burger-button"
          onClick={() => setIsMenuOpen(!isMenuOpen)}
          aria-label="Toggle menu"
        >
          <span></span>
          <span></span>
          <span></span>
        </button>

        {/* Меню */}
        {isMenuOpen && (
          <nav className="mobile-menu">
            <a href="/">Home</a>
            <a href="/about">About</a>
            <a href="/contact">Contact</a>
          </nav>
        )}
      </nav>
    </header>
  );
}

CSS для анимации:

.burger-button {
  display: none;
  flex-direction: column;
  gap: 6px;
  background: none;
  border: none;
  cursor: pointer;
}

.burger-button span {
  width: 24px;
  height: 3px;
  background: currentColor;
  transition: all 0.3s ease;
}

/* Анимация при открытии меню */
.burger-button.active span:nth-child(1) {
  transform: rotate(45deg) translateY(12px);
}

.burger-button.active span:nth-child(2) {
  opacity: 0;
}

.burger-button.active span:nth-child(3) {
  transform: rotate(-45deg) translateY(-12px);
}

/* Мобильное меню */
.mobile-menu {
  position: fixed;
  top: 60px;
  left: 0;
  right: 0;
  background: white;
  border-bottom: 1px solid #eee;
  animation: slideDown 0.3s ease;
}

@keyframes slideDown {
  from {
    transform: translateY(-100%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

/* Показывать на мобильных */
@media (max-width: 768px) {
  .burger-button {
    display: flex;
  }
  
  .desktop-menu {
    display: none;
  }
}

Способ 2: Свайп (жест на мобильном)

Открытие меню жестом с края экрана.

import { useState, useRef } from 'react';

function Header() {
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  const startXRef = useRef(0);

  const handleTouchStart = (e: React.TouchEvent) => {
    startXRef.current = e.touches[0].clientX;
  };

  const handleTouchEnd = (e: React.TouchEvent) => {
    const endX = e.changedTouches[0].clientX;
    const diffX = endX - startXRef.current;

    // Свайп справа налево > 50px = открыть меню
    if (diffX > 50 && startXRef.current < 50) {
      setIsMenuOpen(true);
    }
    // Свайп слева направо > 100px = закрыть меню
    if (diffX < -100 && isMenuOpen) {
      setIsMenuOpen(false);
    }
  };

  return (
    <div onTouchStart={handleTouchStart} onTouchEnd={handleTouchEnd}>
      {/* Контент */}
      {isMenuOpen && <nav className="mobile-menu">...</nav>}
    </div>
  );
}

Используй библиотеку для более удобного swipe:

import { useSwipeable } from 'react-swipeable';

function Header() {
  const [isMenuOpen, setIsMenuOpen] = useState(false);

  const handlers = useSwipeable({
    onSwipedLeft: () => setIsMenuOpen(false),
    onSwipedRight: () => setIsMenuOpen(true),
    trackMouse: false,
  });

  return (
    <div {...handlers}>
      {isMenuOpen && <nav className="mobile-menu">...</nav>}
    </div>
  );
}

Способ 3: Ссылка в меню (desktop)

На десктопе обычное меню в header.

function Header() {
  return (
    <header className="header">
      <nav className="desktop-menu">
        <a href="/">Home</a>
        <a href="/about">About</a>
        <a href="/services">Services</a>
        <a href="/contact">Contact</a>
      </nav>
    </header>
  );
}

// CSS
.desktop-menu {
  display: flex;
  gap: 2rem;
}

@media (max-width: 768px) {
  .desktop-menu {
    display: none;  /* Скрыть на мобильных */
  }
}

Способ 4: Overlay/Backdrop клик (закрытие)

Когда меню открыто, нажимаешь на полупрозрачный фон — меню закрывается.

function MobileMenu() {
  const [isMenuOpen, setIsMenuOpen] = useState(false);

  return (
    <>
      {/* Backdrop (полупрозрачный фон) */}
      {isMenuOpen && (
        <div
          className="backdrop"
          onClick={() => setIsMenuOpen(false)}
          role="button"
          tabIndex={0}
        />
      )}

      {/* Меню */}
      {isMenuOpen && (
        <nav className="mobile-menu" onClick={(e) => e.stopPropagation()}>
          <a href="/">Home</a>
          <a href="/about">About</a>
        </nav>
      )}
    </>
  );
}

// CSS
.backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 999;
  animation: fadeIn 0.3s ease;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.mobile-menu {
  position: fixed;
  top: 0;
  left: 0;
  width: 250px;  /* Ширина меню */
  height: 100vh;
  background: white;
  z-index: 1000;
  animation: slideInLeft 0.3s ease;
  display: flex;
  flex-direction: column;
}

@keyframes slideInLeft {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}

Способ 5: Клавиатура (ESC закрыть)

Нажатие ESC закрывает меню.

import { useEffect } from 'react';

function MobileMenu() {
  const [isMenuOpen, setIsMenuOpen] = useState(false);

  useEffect(() => {
    const handleEscape = (e: KeyboardEvent) => {
      if (e.key === 'Escape' && isMenuOpen) {
        setIsMenuOpen(false);
      }
    };

    document.addEventListener('keydown', handleEscape);
    return () => document.removeEventListener('keydown', handleEscape);
  }, [isMenuOpen]);

  return (
    // JSX
  );
}

Способ 6: Window resize (адаптивность)

Когда меняется размер окна, меню может закрываться/открываться автоматически.

function Header() {
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  const [isMobile, setIsMobile] = useState(window.innerWidth < 768);

  useEffect(() => {
    const handleResize = () => {
      const nowIsMobile = window.innerWidth < 768;
      setIsMobile(nowIsMobile);
      
      // Если открыли окно на полный экран, закрыть меню
      if (!nowIsMobile && isMenuOpen) {
        setIsMenuOpen(false);
      }
    };

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, [isMenuOpen]);

  return (
    <header>
      {isMobile ? (
        <button onClick={() => setIsMenuOpen(!isMenuOpen)}>☰</button>
      ) : (
        <nav className="desktop-menu">...</nav>
      )}
    </header>
  );
}

Полный пример: современное бургер меню

import { useState, useEffect } from 'react';
import './Header.css';

function Header() {
  const [isMenuOpen, setIsMenuOpen] = useState(false);
  const [isMobile, setIsMobile] = useState(false);

  // Проверяем размер экрана
  useEffect(() => {
    const checkMobile = () => {
      setIsMobile(window.innerWidth < 768);
      if (window.innerWidth >= 768) {
        setIsMenuOpen(false);
      }
    };

    window.addEventListener('resize', checkMobile);
    checkMobile();
    return () => window.removeEventListener('resize', checkMobile);
  }, []);

  // Закрываем меню при нажатии ESC
  useEffect(() => {
    const handleEscape = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        setIsMenuOpen(false);
      }
    };

    if (isMenuOpen) {
      document.addEventListener('keydown', handleEscape);
      document.body.style.overflow = 'hidden'; // Запретить скролл
    }

    return () => {
      document.removeEventListener('keydown', handleEscape);
      document.body.style.overflow = 'auto';
    };
  }, [isMenuOpen]);

  const menuItems = [
    { label: 'Home', href: '/' },
    { label: 'About', href: '/about' },
    { label: 'Services', href: '/services' },
    { label: 'Contact', href: '/contact' },
  ];

  return (
    <header className="header">
      <div className="header-content">
        <div className="logo">Logo</div>

        {/* Desktop меню */}
        <nav className="desktop-menu">
          {menuItems.map((item) => (
            <a key={item.href} href={item.href}>
              {item.label}
            </a>
          ))}
        </nav>

        {/* Mobile burger button */}
        {isMobile && (
          <button
            className={`burger-button ${isMenuOpen ? 'active' : ''}`}
            onClick={() => setIsMenuOpen(!isMenuOpen)}
            aria-label="Toggle menu"
            aria-expanded={isMenuOpen}
          >
            <span></span>
            <span></span>
            <span></span>
          </button>
        )}
      </div>

      {/* Mobile меню */}
      {isMobile && isMenuOpen && (
        <>
          {/* Backdrop */}
          <div
            className="backdrop"
            onClick={() => setIsMenuOpen(false)}
          />

          {/* Menu */}
          <nav className="mobile-menu">
            {menuItems.map((item) => (
              <a
                key={item.href}
                href={item.href}
                onClick={() => setIsMenuOpen(false)}
              >
                {item.label}
              </a>
            ))}
          </nav>
        </>
      )}
    </header>
  );
}

export default Header;

CSS:

.header {
  position: relative;
  background: white;
  border-bottom: 1px solid #eee;
}

.header-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
  max-width: 1200px;
  margin: 0 auto;
}

.desktop-menu {
  display: flex;
  gap: 2rem;
}

/* Burger button */
.burger-button {
  display: none;
  flex-direction: column;
  gap: 6px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
}

.burger-button span {
  width: 24px;
  height: 3px;
  background: currentColor;
  transition: all 0.3s ease;
}

.burger-button.active span:nth-child(1) {
  transform: rotate(45deg) translateY(12px);
}

.burger-button.active span:nth-child(2) {
  opacity: 0;
}

.burger-button.active span:nth-child(3) {
  transform: rotate(-45deg) translateY(-12px);
}

/* Mobile меню */
.backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 999;
  animation: fadeIn 0.3s ease;
}

.mobile-menu {
  position: fixed;
  top: 60px;
  left: 0;
  right: 0;
  background: white;
  display: flex;
  flex-direction: column;
  z-index: 1000;
  animation: slideDown 0.3s ease;
  max-height: calc(100vh - 60px);
  overflow-y: auto;
}

.mobile-menu a {
  padding: 1rem;
  border-bottom: 1px solid #eee;
  text-decoration: none;
  color: inherit;
}

.mobile-menu a:active {
  background: #f0f0f0;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes slideDown {
  from {
    transform: translateY(-100%);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

/* Мобильные */
@media (max-width: 768px) {
  .burger-button {
    display: flex;
  }

  .desktop-menu {
    display: none;
  }
}

Best Practices

  1. Accessibility (доступность):

    <button
      aria-label="Toggle navigation menu"
      aria-expanded={isMenuOpen}
      aria-controls="mobile-menu"
    >
    
  2. Performance:

    • Используй CSS transitions вместо JavaScript анимаций
    • Лениво рендери меню (условный рендер)
    • Дебаунс resize события
  3. UX:

    • Закрывай меню при клике на ссылку
    • Поддерживай ESC для закрытия
    • Запретри скролл body при открытом меню
    • Используй плавные анимации

Вывод

Бургер меню можно открыть за счет:

  1. Клик на иконку — основной способ
  2. Свайп — для удобства на мобильных
  3. Desktop меню — обычные ссылки
  4. Backdrop клик — закрытие
  5. ESC клавиша — улучшение UX
  6. Window resize — адаптивность

Современное меню должно поддерживать все эти способы для лучшей UX!