☰ CSS · JavaScript · 반응형 패턴

햄버거 메뉴 (Hamburger Menu)
완전 정복 가이드

모바일 화면에서 ☰ 아이콘 한 번에 열리는 그 네비게이션.
원리부터 슬라이드·드롭다운·X자 애니메이션까지 — 복붙 한 번에 내 사이트에 바로 적용해요.

⏱️ 약 10분 📅 2026년 4월 🏷️ CSS · JS · 반응형 👶 입문 난이도
① 개념

햄버거 메뉴란 무엇인가요?

세 줄짜리 아이콘(☰) 뒤에 숨겨진 네비게이션 — 모바일 UI의 핵심 패턴

모바일 앱이나 웹사이트 상단 구석에 줄 세 개짜리 아이콘(☰)을 눌렀을 때 메뉴가 쫙 펼쳐진 경험, 다들 있으시죠? 그게 바로 햄버거 메뉴(Hamburger Menu)예요. 세 개의 가로선이 마치 햄버거를 옆에서 본 모습처럼 생겼다고 해서 붙은 이름이에요. 위 빵 → 패티 → 아래 빵, 딱 3줄이죠.

데스크탑 화면에서는 링크들을 가로로 쭉 나열해도 충분한 공간이 있지만, 모바일 화면은 너비가 좁아서 메뉴 항목들이 다 들어가지 않아요. 그래서 768px 이하 같은 특정 너비 기준으로 메뉴를 숨기고, ☰ 버튼 하나만 보여두는 거예요. 버튼을 누르면 메뉴가 다시 나타나고, 다시 누르거나 바깥을 클릭하면 닫히죠.

구현 원리는 간단해요. CSS @media 쿼리로 작은 화면에서 일반 메뉴를 display: none으로 숨기고, ☰ 버튼을 display: flex로 보여줘요. 그 버튼을 클릭하면 JavaScript가 메뉴 요소에 open 클래스를 추가하거나 제거하고, CSS transition이 부드러운 애니메이션을 담당해요.

📱

모바일 공간 절약

좁은 모바일 화면에서 네비게이션 항목들을 하나의 아이콘 뒤에 깔끔하게 숨겨요. UX의 핵심 패턴이에요.

🎯

반응형 디자인 필수

모바일과 데스크탑을 동시에 지원하는 반응형 웹사이트라면 햄버거 메뉴는 거의 필수 구성 요소예요.

HTML + CSS + JS

별도 라이브러리 없이 순수 코드로 만들 수 있어요. 미디어 쿼리, 클래스 토글, 트랜지션만 알면 완성!

다양한 애니메이션

슬라이드, 드롭다운, 페이드인 등 열리는 방식에 따라 사이트의 분위기가 달라져요. 골라 쓰세요.

💡

언제 햄버거 메뉴를 쓰나요? 보통 768px 이하 (태블릿·모바일) 화면에서 사용해요. 데스크탑에서는 가로 네비게이션을 그대로 보여주고, 모바일에서만 햄버거 메뉴로 전환하는 게 일반적인 패턴이에요. CSS @media (max-width: 768px)를 기준으로 스타일을 나눠요.

☰ 기호의 유니코드U+2630이에요. HTML에서는 &#9776; 또는 그냥 ☰을 직접 입력해도 되고, 실제 프로젝트에서는 CSS로 만든 세 개의 <span> 또는 SVG 아이콘을 주로 사용해요. 코드로 만들면 열릴 때 X자(✕)로 바뀌는 애니메이션을 쉽게 추가할 수 있거든요.

② 유형 갤러리

3가지 대표 햄버거 메뉴 패턴

어떤 스타일이 내 사이트에 어울릴까요? 직접 클릭해서 동작을 확인해보세요.

PREVIEW · CLICK
MY SITE
소개
서비스
문의
슬라이드 사이드바
왼쪽에서 패널이 밀려나오는 방식. 깊은 메뉴 계층에 적합하고, 고급스러운 느낌을 줘요.
transform translateX 추천
PREVIEW · CLICK
드롭다운 메뉴
네비게이션 바 아래로 메뉴가 펼쳐지는 방식. 구현이 간단하고 직관적이에요.
scaleY max-height 가장 많이 사용
PREVIEW · CLICK
☰ 클릭하면
✕ 로 바뀌어요
X자 애니메이션
☰ 아이콘이 ✕로 부드럽게 변환되는 애니메이션. 열림/닫힘 상태를 직관적으로 표현해요.
rotate opacity transform-origin
③ 코드 해설

코드 한 줄 한 줄 뜯어보기

HTML 구조부터 CSS 애니메이션, JS 토글 로직까지 완전한 코드와 설명

<header> > <nav> 구조
HTML 시맨틱 구조
접근성을 위해 <nav> 태그를 사용해요. 안에 로고, 데스크탑 메뉴, 햄버거 버튼을 나란히 배치해요.
header > nav ├── .logo ├── .nav-menu /* 데스크탑 메뉴 */ └── .hamburger /* ☰ 버튼 */
@media (max-width: 768px)
미디어 쿼리 분기
768px보다 작은 화면에서 데스크탑 메뉴를 숨기고 햄버거 버튼을 보여줘요. 반응형의 핵심이에요.
.nav-menu { display: flex; } .hamburger { display: none; } /* 모바일 */ @media (max-width: 768px) { .nav-menu { display: none; } .hamburger { display: flex; } }
classList.toggle('open')
JS 클래스 토글
버튼을 클릭할 때마다 open 클래스를 추가/제거해요. CSS는 이 클래스의 유무로 애니메이션을 제어해요.
btn.addEventListener('click', () => { menu.classList.toggle('open'); btn.classList.toggle('open'); });
max-height: 0 → 300px
슬라이드 애니메이션 비법
heightauto에서 transition이 안 돼요. 대신 max-height를 0에서 충분히 큰 값으로 변경하면 부드럽게 펼쳐져요.
.nav-menu { max-height: 0; overflow: hidden; transition: max-height .35s; } .nav-menu.open { max-height: 300px; }
document.addEventListener('click')
바깥 클릭 시 닫기
문서 전체에 클릭 이벤트를 달고, 클릭 대상이 nav 안에 없으면 메뉴를 닫아요. UX 필수 기능이에요.
document.addEventListener('click', (e) => { if (!nav.contains(e.target)) { close(); } });
transform: rotate(45deg)
X자 변환 트릭
3개의 선을 CSS로 만들고, 위·아래 선은 회전, 가운데 선은 투명하게 만들면 ☰ → ✕ 변환 효과가 완성돼요.
.open :nth-child(1) { transform: translateY(7px) rotate(45deg); } .open :nth-child(2) { opacity: 0; } .open :nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
<!-- HTML 구조 -->
<header class="site-header">
  <nav class="navbar">

    <!-- 로고 -->
    <a href="/" class="nav-logo">MySite</a>

    <!-- 데스크탑 + 모바일 메뉴 -->
    <ul class="nav-menu" id="navMenu">
      <li><a href="#"></a></li>
      <li><a href="#">소개</a></li>
      <li><a href="#">서비스</a></li>
      <li><a href="#">문의하기</a></li>
    </ul>

    <!-- 햄버거 버튼 -->
    <button
      class="hamburger"
      id="hamburgerBtn"
      aria-label="메뉴 열기"
      aria-expanded="false"
    >
      <span class="hline"></span>
      <span class="hline"></span>
      <span class="hline"></span>
    </button>

  </nav>
</header>
/* ── 기본 네비게이션 ── */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  background: #fff;
  box-shadow: 0 1px 8px rgba(0,0,0,.08);
  z-index: 100;
}

.navbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px;
  height: 60px;
}

/* ── 데스크탑 메뉴 ── */
.nav-menu {
  display: flex;
  list-style: none;
  gap: 8px;
}

.nav-menu a {
  padding: 6px 14px;
  border-radius: 6px;
  color: #374151;
  font-weight: 500;
  text-decoration: none;
  transition: background .15s;
}
.nav-menu a:hover { background: #f3f4f6; }

/* ── 햄버거 버튼 ── */
.hamburger {
  display: none; /* 기본은 숨김 */
  flex-direction: column;
  gap: 5px;
  padding: 8px;
  background: none;
  border: none;
  cursor: pointer;
}

.hline {
  width: 22px; height: 2px;
  background: #111827;
  border-radius: 2px;
  transition: transform .3s, opacity .3s;
  transform-origin: center;
}

/* ☰ → ✕ 애니메이션 */
.hamburger.open .hline:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.hamburger.open .hline:nth-child(2) {
  opacity: 0;
  transform: scaleX(0);
}
.hamburger.open .hline:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* ── 모바일 반응형 ── */
@media (max-width: 768px) {
  .hamburger { display: flex; }

  .nav-menu {
    position: absolute;
    top: 60px; left: 0; right: 0;
    flex-direction: column;
    background: #fff;
    box-shadow: 0 8px 24px rgba(0,0,0,.10);
    max-height: 0;
    overflow: hidden;
    transition: max-height .35s cubic-bezier(.4,0,.2,1);
    padding: 0;
    gap: 0;
  }

  .nav-menu.open {
    max-height: 400px;
    padding: 8px 0;
  }

  .nav-menu li a {
    display: block;
    padding: 12px 24px;
    border-radius: 0;
    border-bottom: 1px solid #f3f4f6;
  }
}
// 요소 참조
const btn  = document.getElementById('hamburgerBtn');
const menu = document.getElementById('navMenu');
const nav  = document.querySelector('.navbar');

// 메뉴 열기 / 닫기 함수
function openMenu() {
  menu.classList.add('open');
  btn.classList.add('open');
  btn.setAttribute('aria-expanded', 'true');
  btn.setAttribute('aria-label', '메뉴 닫기');
  document.body.style.overflow = 'hidden'; // 스크롤 방지
}

function closeMenu() {
  menu.classList.remove('open');
  btn.classList.remove('open');
  btn.setAttribute('aria-expanded', 'false');
  btn.setAttribute('aria-label', '메뉴 열기');
  document.body.style.overflow = '';
}

// 버튼 클릭 시 토글
btn.addEventListener('click', () => {
  if (menu.classList.contains('open')) {
    closeMenu();
  } else {
    openMenu();
  }
});

// 바깥 클릭 시 닫기
document.addEventListener('click', (e) => {
  if (!nav.contains(e.target)) {
    closeMenu();
  }
});

// 메뉴 항목 클릭 시 닫기
menu.querySelectorAll('a').forEach(link => {
  link.addEventListener('click', () => {
    closeMenu();
  });
});

// ESC 키로 닫기
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape') closeMenu();
});
④ 인터랙티브 데모

직접 조작해보는 햄버거 메뉴

데스크탑 / 모바일 모드를 전환하면서 실제 동작을 확인해보세요.

live-demo.html
페이지 콘텐츠 영역
모바일 모드에서 ☰ 버튼을 눌러보세요
⑤ AI 프롬프트 팁

AI에게 정확하게 요청하는 법

바이브 코딩으로 햄버거 메뉴를 만들 때 이 프롬프트를 그대로 복붙하세요.

✦ 바이브코더 추천 프롬프트

아래 프롬프트를 Claude, ChatGPT, Cursor 등 AI 코딩 도구에 붙여넣으면 바로 작동하는 코드를 받을 수 있어요. 필요에 따라 메뉴 항목이나 색상을 바꿔서 사용하세요.

내 사이트 상단 네비게이션을 모바일에서 햄버거 메뉴로 바꿔줘.

요구사항:
- 768px 이하에서 기존 메뉴를 숨기고 ☰ 버튼을 보여줘
- 버튼 클릭 시 메뉴가 아래로 슬라이드되어 나타나게 해줘 (max-height 트릭 사용)
- ☰ 버튼이 클릭되면 ✕ 로 바뀌는 CSS 애니메이션 추가해줘
- 메뉴 항목: 홈, 소개, 서비스, 문의하기
- 메뉴 항목 클릭 시 메뉴가 닫히게 해줘
- 바깥 영역 클릭 시 메뉴가 닫히게 해줘
- ESC 키로도 닫히게 해줘
- aria-expanded 접근성 속성도 올바르게 처리해줘
💡

더 구체적으로 요청하면 더 좋은 코드가 나와요! "슬라이드 사이드바 방식으로 만들어줘" 또는 "왼쪽에서 밀려나오는 오버레이 패널 방식으로" 처럼 원하는 동작을 명확히 설명하면 AI가 정확히 맞춰줘요.

기존 코드가 있다면 "아래 코드에서 nav 부분을 햄버거 메뉴로 바꿔줘:"라고 시작하고 코드를 붙여넣으세요. 훨씬 정확한 결과를 받을 수 있어요.

⑥ FAQ

자주 묻는 질문

햄버거 메뉴를 처음 만들 때 자주 마주치는 문제들을 정리했어요.

데스크탑에서도 햄버거 버튼이 보여요. 어떻게 숨기나요?

미디어 쿼리 밖에서 .hamburger { display: none; }으로 기본 숨김 처리를 먼저 해주세요. 그다음 @media (max-width: 768px) 안에서 .hamburger { display: flex; }로 모바일에서만 보이게 하면 돼요.

반대로 데스크탑 메뉴는 기본적으로 display: flex이고, 미디어 쿼리 안에서 display: none으로 숨겨야 해요. 이 두 가지를 쌍으로 처리해야 해요.

메뉴가 열릴 때 화면이 밀려요 (스크롤이 생겨요).

메뉴가 열릴 때 배경 스크롤을 막지 않아서 생기는 현상이에요. JavaScript에서 메뉴를 열 때 document.body.style.overflow = 'hidden'을 추가하고, 닫을 때 document.body.style.overflow = ''으로 되돌리면 해결돼요.

특히 풀스크린 드롭다운이나 사이드바 방식에서는 이 처리가 꼭 필요해요.

다른 페이지로 이동하면 메뉴가 닫히지 않아요.

각 메뉴 항목(<a> 태그)에 클릭 이벤트를 달아서 closeMenu()를 호출해야 해요.

menu.querySelectorAll('a').forEach(link => link.addEventListener('click', closeMenu))처럼 모든 링크에 한 번에 처리하면 편해요. SPA(싱글 페이지 앱)에서는 라우터 변경 이벤트에서도 닫아줘야 해요.

height: auto에서 슬라이드 애니메이션이 작동하지 않아요.

CSS transitionheight: auto를 지원하지 않아요. 이때 사용하는 꼼수가 max-height 트릭이에요. 닫혔을 때 max-height: 0; overflow: hidden;으로 설정하고, 열렸을 때 max-height: 400px;처럼 충분히 큰 값으로 바꾸면 부드럽게 펼쳐져요.

단, max-height 값이 실제 내용보다 훨씬 크면 닫힐 때 먼저 줄어들고 나중에 사라지는 느낌이 날 수 있으니, 내용 높이와 너무 차이나지 않게 설정하세요.

스크롤해도 메뉴가 고정되지 않아요.

헤더에 position: fixed; top: 0; left: 0; right: 0;를 적용해야 해요. 그리고 <body>padding-top: 60px;(헤더 높이만큼)을 추가해야 헤더 뒤에 콘텐츠가 가려지지 않아요.

접근성(키보드, 스크린 리더)을 고려해야 할까요?

네, 꼭 챙겨야 해요. 햄버거 버튼에 aria-label="메뉴 열기"aria-expanded="false"를 추가하고, 메뉴가 열리면 aria-expanded="true"로 업데이트해요. 또한 ESC 키로 닫히도록 처리하면 키보드 사용자도 불편 없이 이용할 수 있어요.

버튼에 <button> 태그를 사용하면 키보드 포커스가 자동으로 처리되니, <div><span>이 아닌 <button>을 쓰는 것을 권장해요.