- 설명
2단 메뉴(또는 드롭다운 메뉴, 서브 메뉴)를 구성하는 방법은 다양하지만, SEO와 사용자 경험(UX)을 모두 고려하여 효율적으로 만드는 것이 중요합니다. 주로 HTML, CSS, JavaScript를 사용하여 구현합니다.
1. HTML 구조 (뼈대)
2단 메뉴의 HTML 구조는 주로 중첩된(nested) 목록을 사용합니다. 이는 검색 엔진과 스크린 리더가 메뉴 계층을 이해하는 데 가장 적합한 방식입니다.
HTML
<nav role="navigation">
<ul class="main-menu">
<li>
<a href="/">홈</a>
</li>
<li>
<a href="/products">제품</a>
<ul class="sub-menu"> <li><a href="/products/category1">카테고리 1</a></li>
<li><a href="/products/category2">카테고리 2</a></li>
<li><a href="/products/category3">카테고리 3</a></li>
</ul>
</li>
<li>
<a href="/services">서비스</a>
<ul class="sub-menu">
<li><a href="/services/web">웹 개발</a></li>
<li><a href="/services/mobile">모바일 앱</a></li>
</ul>
</li>
<li>
<a href="/about">회사 소개</a>
</li>
<li>
<a href="/contact">문의</a>
</li>
</ul>
</nav>
설명:
<nav role="navigation">
: 전체 메뉴 영역을 의미하며, role="navigation"
은 접근성을 위한 시맨틱 역할을 부여합니다.
<ul class="main-menu">
: 1단 메뉴(최상위 메뉴)를 감싸는 컨테이너입니다.
<li>
: 각 메뉴 항목을 나타냅니다.
<a href="...">
: 각 메뉴 항목의 실제 링크입니다. 링크 텍스트는 해당 페이지의 내용을 명확히 설명하는 키워드를 포함하는 것이 SEO에 좋습니다.
<ul class="sub-menu">
: 2단 메뉴(서브 메뉴)를 감싸는 컨테이너입니다. 이 <ul>
은 해당 1단 메뉴 <li>
안에 중첩되어야 합니다. 처음에는 CSS로 숨겨둡니다.
접근성 고려: aria-haspopup="true"
와 aria-expanded="false"
같은 ARIA 속성을 <a>
태그에 추가하여 서브 메뉴가 있음을 스크린 리더 사용자에게 알릴 수 있습니다. (자바스크립트와 함께 사용)
2. CSS 스타일링 (숨기기 및 보이기)
CSS는 2단 메뉴를 시각적으로 숨겨두었다가, 마우스 오버(hover)나 클릭 시 나타나도록 만듭니다.
CSS
/* 기본 메뉴 스타일 */
.main-menu {
list-style: none; /* 목록 마커 제거 */
margin: 0;
padding: 0;
display: flex; /* 가로로 정렬 */
background-color: #333;
}
.main-menu li {
position: relative; /* 서브 메뉴의 위치 기준 */
}
.main-menu li a {
display: block; /* 링크 영역 확장 */
padding: 15px 20px;
color: white;
text-decoration: none;
white-space: nowrap; /* 링크 텍스트 줄바꿈 방지 */
}
.main-menu li a:hover {
background-color: #555;
}
/* 2단 메뉴 (서브 메뉴) 스타일 */
.sub-menu {
list-style: none;
margin: 0;
padding: 0;
position: absolute; /* 1단 메뉴를 기준으로 배치 */
top: 100%; /* 1단 메뉴 바로 아래에 위치 */
left: 0;
background-color: #444;
min-width: 180px; /* 최소 너비 설정 */
z-index: 100; /* 다른 요소 위에 오도록 */
/* 기본적으로 숨김 */
display: none;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease; /* 부드러운 전환 효과 */
}
.sub-menu li a {
padding: 10px 20px; /* 서브 메뉴 항목 패딩 */
color: #eee;
}
.sub-menu li a:hover {
background-color: #666;
}
/* 마우스 오버 시 2단 메뉴 보이기 */
.main-menu li:hover > .sub-menu {
display: block;
opacity: 1;
visibility: visible;
}
설명:
position: relative;
(1단 메뉴 li
): 서브 메뉴(position: absolute;
)의 위치 기준이 됩니다.
position: absolute;
(2단 메뉴 ul.sub-menu
): 서브 메뉴를 1단 메뉴(li
) 기준으로 배치하여 페이지 흐름에 영향을 주지 않게 합니다.
top: 100%; left: 0;
: 1단 메뉴 아이템 바로 아래에 서브 메뉴가 시작되도록 합니다.
display: none; opacity: 0; visibility: hidden;
: 서브 메뉴를 처음에는 완전히 숨깁니다. opacity
와 visibility
는 transition
과 함께 사용하여 부드러운 효과를 만듭니다.
.main-menu li:hover > .sub-menu
: 1단 메뉴 항목에 마우스를 올렸을 때 (hover), 바로 아래 자식인 2단 메뉴(sub-menu
)를 보이게 합니다.
3. JavaScript (모바일 및 접근성 고려)
CSS :hover
만으로는 모바일 환경에서 터치 이벤트 처리가 어렵고, 키보드 접근성도 부족합니다. JavaScript를 사용하여 이를 보완합니다.
JavaScript
document.addEventListener('DOMContentLoaded', function() {
const mainMenuItems = document.querySelectorAll('.main-menu > li');
mainMenuItems.forEach(item => {
const subMenu = item.querySelector('.sub-menu');
const mainLink = item.querySelector('a');
if (subMenu) {
// ARIA 속성 추가
mainLink.setAttribute('aria-haspopup', 'true');
mainLink.setAttribute('aria-expanded', 'false');
// 마우스 오버/아웃 이벤트 (데스크톱)
item.addEventListener('mouseenter', function() {
subMenu.style.display = 'block';
setTimeout(() => { // 부드러운 전환을 위해 약간의 지연
subMenu.style.opacity = '1';
subMenu.style.visibility = 'visible';
mainLink.setAttribute('aria-expanded', 'true');
}, 10);
});
item.addEventListener('mouseleave', function() {
subMenu.style.opacity = '0';
subMenu.style.visibility = 'hidden';
mainLink.setAttribute('aria-expanded', 'false');
setTimeout(() => { // 숨긴 후 display none으로 전환
subMenu.style.display = 'none';
}, 300); // transition 시간과 일치
});
// 모바일 터치 이벤트 (클릭 시 토글)
mainLink.addEventListener('click', function(e) {
// 이미 하이퍼링크가 있는 경우, 페이지 이동을 막고 메뉴만 토글
// 만약 서브 메뉴를 클릭해야만 페이지 이동하도록 할 경우 이 부분을 사용
// if (window.innerWidth <= 768) { // 모바일 환경 기준 (예시)
// e.preventDefault(); // 기본 링크 동작 막기
// // 다른 열린 서브 메뉴 닫기 (선택 사항)
// mainMenuItems.forEach(otherItem => {
// if (otherItem !== item) {
// const otherSubMenu = otherItem.querySelector('.sub-menu');
// const otherMainLink = otherItem.querySelector('a');
// if (otherSubMenu && otherSubMenu.style.display === 'block') {
// otherSubMenu.style.opacity = '0';
// otherSubMenu.style.visibility = 'hidden';
// otherMainLink.setAttribute('aria-expanded', 'false');
// setTimeout(() => otherSubMenu.style.display = 'none', 300);
// }
// }
// });
// // 현재 서브 메뉴 토글
// if (subMenu.style.display === 'block') {
// subMenu.style.opacity = '0';
// subMenu.style.visibility = 'hidden';
// mainLink.setAttribute('aria-expanded', 'false');
// setTimeout(() => subMenu.style.display = 'none', 300);
// } else {
// subMenu.style.display = 'block';
// setTimeout(() => {
// subMenu.style.opacity = '1';
// subMenu.style.visibility = 'visible';
// mainLink.setAttribute('aria-expanded', 'true');
// }, 10);
// }
// }
});
}
});
});
설명:
aria-haspopup="true"
/ aria-expanded="false/true"
: 스크린 리더 사용자에게 이 링크가 팝업/서브 메뉴를 가지고 있으며, 현재 열려있는지 닫혀있는지 알려줍니다.
mouseenter
/mouseleave
: CSS :hover
와 유사하게 동작하지만, JavaScript로 추가적인 제어를 할 수 있습니다.
모바일 터치 처리 (주석 처리된 부분): 모바일에서는 :hover
가 제대로 작동하지 않으므로, 클릭 이벤트를 사용하여 서브 메뉴를 토글하는 로직이 필요합니다. 위 코드에서는 주석 처리되어 있는데, 주석을 해제하고 미디어 쿼리(window.innerWidth <= 768
)와 결합하여 모바일 환경에서만 작동하도록 구현할 수 있습니다. 주의: 1단 메뉴 링크가 이미 페이지 이동 역할을 하는 경우, 클릭 시 페이지 이동과 서브 메뉴 토글 중 어떤 것을 우선할지 결정해야 합니다. 보통 데스크톱은 hover, 모바일은 클릭 토글을 선호합니다.
4. SEO 및 사용자 경험 고려사항
HTML 구조: 중첩된 <ul><li>
구조는 검색 엔진이 웹사이트의 계층 구조를 이해하는 데 가장 좋습니다.
링크 텍스트: 2단 메뉴의 각 링크 텍스트도 해당 페이지의 내용을 잘 나타내는 키워드를 포함해야 합니다.
접근성:
ARIA 속성 사용은 스크린 리더 사용자가 메뉴를 이해하고 탐색하는 데 큰 도움이 됩니다.
키보드 탐색: Tab
키로 메뉴를 이동하고 Enter
키로 서브 메뉴를 열거나 링크를 활성화할 수 있도록 JavaScript로 Tab 인덱스 및 이벤트 처리를 추가해야 합니다.
포커스 관리: 서브 메뉴가 열렸을 때 키보드 포커스가 서브 메뉴 항목으로 이동하도록 처리해야 합니다.
모바일 반응형 디자인: 작은 화면에서는 드롭다운 메뉴가 사용자 경험을 해칠 수 있으므로, 햄버거 메뉴 등으로 전환하여 구현하는 것이 일반적입니다. (위 코드 예시에는 포함되지 않음)
CSS display: none;
vs visibility: hidden;
:
display: none;
은 요소가 공간을 차지하지 않도록 완전히 숨깁니다. 검색 엔진은 display: none;
으로 숨겨진 콘텐츠를 중요하지 않게 보거나 아예 크롤링하지 않을 수도 있다는 논란이 있었지만, 일반적으로는 잘 크롤링합니다.
visibility: hidden;
은 요소가 공간을 차지하지만 시각적으로만 숨깁니다.
opacity: 0;
는 요소가 공간을 차지하고 시각적으로 투명하게 숨깁니다.
애니메이션을 위해서는 opacity
와 visibility
를 사용하고, 애니메이션이 끝난 후 완전히 공간을 차지하지 않도록 display: none;
으로 전환하는 것이 일반적입니다.
2단 메뉴는 복잡해 보일 수 있지만, 위 가이드라인을 따르면 SEO와 UX를 모두 만족시키는 효과적인 메뉴를 만들 수 있습니다.