본문 바로가기

카테고리 없음

Vue + Tailwind에서 반응형 메뉴 구현 시 흔히 겪는 문제와 해결법

반응형

웹사이트에서 상단 메뉴를 구현할 때, PC에서는 hover로 메뉴가 열리고, 모바일에서는 클릭으로 메뉴가 열리는 방식을 자주 사용합니다.

Vue 3 + <script setup> + TailwindCSS 환경에서 반응형 디자인이 아닌 PC와 동일한 디자인을 적용할 때 겪은 시행착오와 해결 방법을 정리합니다.


문제 상황

  1. 모바일에서 동작을 위해 상위 메뉴 클릭시 모바일 여부와 메뉴 오픈 여부를 체크하여 하위메뉴를 보여주도록 적용한 뒤, PC에서는 hover로 하위 메뉴가 열리지만, 마우스를 아래로 내리는 순간 메뉴가 사라짐
  2. 모바일에서는 클릭으로 하위 메뉴를 열어야 하는데, viewport가 고정되어 있어 window.innerWidth로는 모바일인지 구분이 안 됨
  3. v-show로 메뉴를 열어도 class="hidden"이 같이 적용돼서 메뉴가 안 보임

문제 원인과 해결 방법

1. PC에서 hover 메뉴가 바로 닫히는 문제

원인
상단 메뉴에만 @mouseleave가 적용돼 있어, 사용자가 마우스를 아래로 이동하면 하위 메뉴를 클릭하기 전에 사라집니다.

해결
상단 메뉴와 하위 메뉴를 같은 div로 감싸고, 이 래퍼에 @mouseenter, @mouseleave 이벤트를 줘야 합니다.

<div
  class="relative"
  @mouseenter="isHoverMenu = true"
  @mouseleave="isHoverMenu = false"
>
  <!-- 상단 메뉴 -->
  <div class="flex"> ... </div>

  <!-- 하위 메뉴 -->
  <div v-show="isHoverMenu" class="absolute top-full"> ... </div>
</div>

2. 모바일 디바이스 구분이 안 되는 문제

원인
<meta name="viewport" content="width=1024"> 설정 때문에 window.innerWidth가 항상 1024로 고정됨

해결
navigator.userAgent를 기반으로 디바이스가 모바일인지 판단해야 함

function isMobileDevice(): boolean {
  return /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
}

onMounted(() => {
  isMobile.value = isMobileDevice();
});

3. v-show로 메뉴를 열어도 안 보이는 문제

원인
v-show는 내부적으로 display: none을 조절하는데, Tailwind의 class="hidden"이 함께 있으면 무조건 숨겨짐

해결
v-show 대신 조건부 :class로 hidden/flex를 제어해야 함

<div :class="[ isOpen ? 'flex' : 'hidden', 'absolute top-full ...' ]">

모바일 클릭, PC hover 둘 다 지원하는 조건

하위 메뉴는 다음 조건으로 보여줄 수 있습니다:

:class="[
  'absolute top-full ...',
  (!isMobile && isHoverMenu) || (isMobile && isMenuOpen) ? 'flex' : 'hidden'
]"

✨ 마무리

Vue + Tailwind로 반응형 메뉴를 만들 때는 PC와 모바일의 동작 방식이 완전히 다르기 때문에 분리해서 처리해야 안정적인 UX를 구현할 수 있습니다.

  • 디바이스 구분은 userAgent 기반으로
  • hover 이벤트는 상단/하위 메뉴 전체 래퍼에서 처리
  • Tailwind의 hidden과 v-show는 동시에 쓰지 않기

구현이 복잡하게 느껴진다면 상단 메뉴와 하위 메뉴를 컴포넌트로 분리해서 각 환경에 맞게 관리하는 것도 좋은 방법입니다.

 

반응형