헤더·네비게이션·메가 메뉴: 대규모 이커머스 사이트 네비게이션 설계

UX 디자인

네비게이션메가 메뉴헤더 설계이커머스 UX정보 구조

이 글은 누구를 위한 것인가

  • 카테고리가 많아져서 메뉴 구조가 복잡해진 이커머스 팀
  • 모바일에서 햄버거 메뉴 클릭율이 너무 낮은 팀
  • 메가 메뉴를 처음 설계하는 UX 디자이너·개발자

들어가며

네비게이션은 "유저가 원하는 것을 빠르게 찾게 돕는" 것이 전부다. 메뉴 항목이 8개 이상이면 메가 메뉴를 고려해야 하고, 모바일에서 햄버거 메뉴는 클릭율이 낮으므로 대안을 찾아야 한다.

이 글은 bluefoxdev.kr의 이커머스 네비게이션 설계 를 참고하여 작성했습니다.


1. 네비게이션 패턴 선택 가이드

[카테고리 수별 네비게이션 패턴]

5개 이하:
  패턴: 수평 탭 네비게이션
  예: 홈 | 상품 | 세일 | 브랜드 | 마이페이지

6-12개:
  패턴: 드롭다운 메뉴
  각 카테고리에 서브메뉴

13개 이상:
  패턴: 메가 메뉴 (2-3단 열 구조)
  카테고리 + 서브카테고리 + 브랜드/추천

[메가 메뉴 내부 구조]
  1열: 주요 카테고리 목록 (세로)
  2열: 선택된 카테고리의 서브카테고리
  3열 (선택): 브랜드, 추천 상품, 배너

[모바일 네비게이션 대안]
  ❌ 햄버거 메뉴: 클릭율 낮음, 발견 어려움
  ✅ 탭 바 (5개 이하): 하단 고정, 항상 보임
  ✅ 검색 우선: 검색창을 전면 배치
  ✅ 카테고리 퀵링크: 홈 화면에 카테고리 아이콘

2. 메가 메뉴 구현

"use client";
import { useState, useRef, useCallback } from "react";

interface Category {
  id: string;
  name: string;
  slug: string;
  subcategories: Subcategory[];
  featuredBrands?: string[];
}

function MegaMenu({ categories }: { categories: Category[] }) {
  const [activeCategory, setActiveCategory] = useState<string | null>(null);
  const closeTimer = useRef<NodeJS.Timeout>();

  const handleMouseEnter = useCallback((categoryId: string) => {
    if (closeTimer.current) clearTimeout(closeTimer.current);
    setActiveCategory(categoryId);
  }, []);

  const handleMouseLeave = useCallback(() => {
    // 약간의 지연으로 실수로 메뉴가 닫히는 것 방지
    closeTimer.current = setTimeout(() => {
      setActiveCategory(null);
    }, 150);
  }, []);

  const activeData = categories.find((c) => c.id === activeCategory);

  return (
    <nav className="relative" onMouseLeave={handleMouseLeave}>
      {/* 카테고리 탭 */}
      <ul className="flex items-center gap-1">
        {categories.map((category) => (
          <li key={category.id}>
            <a
              href={`/category/${category.slug}`}
              className={`px-4 py-5 text-sm font-medium hover:text-blue-600 block ${
                activeCategory === category.id ? "text-blue-600 border-b-2 border-blue-600" : "text-gray-700"
              }`}
              onMouseEnter={() => handleMouseEnter(category.id)}
            >
              {category.name}
            </a>
          </li>
        ))}
      </ul>

      {/* 메가 메뉴 패널 */}
      {activeData && (
        <div
          className="absolute top-full left-0 right-0 bg-white border-t shadow-lg z-50"
          onMouseEnter={() => handleMouseEnter(activeData.id)}
        >
          <div className="max-w-7xl mx-auto px-4 py-6 grid grid-cols-4 gap-8">
            {/* 서브카테고리 그리드 */}
            <div className="col-span-3 grid grid-cols-3 gap-4">
              {activeData.subcategories.map((sub) => (
                <div key={sub.id}>
                  <h3 className="font-semibold text-sm mb-2 text-gray-900">
                    <a href={`/category/${sub.slug}`} className="hover:text-blue-600">
                      {sub.name}
                    </a>
                  </h3>
                  <ul className="space-y-1">
                    {sub.children?.map((child) => (
                      <li key={child.id}>
                        <a
                          href={`/category/${child.slug}`}
                          className="text-sm text-gray-500 hover:text-blue-600"
                        >
                          {child.name}
                        </a>
                      </li>
                    ))}
                  </ul>
                </div>
              ))}
            </div>

            {/* 추천 배너 */}
            <div className="col-span-1">
              <div className="bg-gray-50 rounded-lg p-4">
                <p className="text-xs text-gray-500 mb-2">이번 주 추천</p>
                <a href={`/category/${activeData.slug}/sale`} className="block">
                  <img
                    src={activeData.bannerUrl}
                    alt="추천 배너"
                    className="w-full rounded-lg"
                  />
                </a>
              </div>
            </div>
          </div>
        </div>
      )}
    </nav>
  );
}

마무리

메가 메뉴 설계에서 가장 중요한 것은 "마우스 딜레이 존"이다. 사용자가 대각선으로 마우스를 이동할 때 메뉴가 닫혀버리면 답답하다. 150ms 지연으로 이 문제를 해결하고, 메뉴 호버 영역을 패널까지 연결해야 한다. 모바일에서는 메가 메뉴 대신 검색과 카테고리 퀵링크로 대체하는 것이 전환율에 더 좋다.