CSS / CSS로 드롭다운(Dropdown) 메뉴 만들기
JavaScript 없이 기본 드롭다운 메뉴를 만들려면 HTML의 details·summary로 하위 링크를 열고 닫고, CSS로 펼쳐진 목록의 위치와 모양을 정할 수 있습니다. summary를 누르면 메뉴가 열리고 다시 누르면 닫힙니다. 마우스를 올리는 동작에만 의존하지 않아 키보드와 터치 환경에서도 같은 열기 동작을 사용할 수 있습니다.
열기 동작과 화면 배치를 나누어 설계하기
드롭다운은 상위 항목을 조작하면 그 아래의 링크 목록이 펼쳐지는 구성입니다. HTML의 details는 기본적으로 닫혀 있고, 첫 자식 summary가 열기·닫기 조작부가 됩니다. 브라우저가 open 상태를 관리하므로 CSS에서 숨겨진 체크박스나 클릭 상태를 흉내 낼 필요가 없습니다.
일반 사이트 내비게이션 링크에 role="menu"를 붙이면 화살표 이동 등 별도의 복잡한 키보드 동작까지 기대하게 만들 수 있습니다. 이 예제는 nav와 목록·링크, 브라우저의 기본 펼치기 요소를 사용합니다. summary에 가짜 링크를 넣거나, 링크의 이동 기능과 펼치기 기능을 한 번의 클릭에 동시에 맡기지 않습니다.
전체 예제: 클릭·키보드로 여는 메뉴
아래 코드를 dropdown-menu.html로 저장해 브라우저에서 엽니다. 메뉴의 링크는 예제 파일 안에 실제로 있는 HTML·CSS·JavaScript 설명 위치로 이동합니다. 외부 파일이나 라이브러리는 필요하지 않습니다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>클릭으로 여는 드롭다운 메뉴</title>
<style>
body { margin: 20px; font: 16px/1.6 "Noto Sans KR", sans-serif; color: #203348; }
* { box-sizing: border-box; }
h1 { font-size: 24px; }
.nav { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
padding: 12px; background: #edf3fa; border: 1px solid #8ca3ba; }
.nav > a, summary { padding: 10px 14px; min-height: 44px; }
.dropdown { position: relative; }
summary { cursor: pointer; }
.panel { position: absolute; top: 100%; left: 0; z-index: 10;
width: min(250px, calc(100vw - 64px)); margin: 0; padding: 8px;
list-style: none; border: 1px solid #8ca3ba; border-radius: 6px;
background: white; box-shadow: 0 6px 18px rgb(0 0 0 / 0.12); }
.panel a { display: block; padding: 10px; color: #154d82; overflow-wrap: anywhere; }
.panel a:hover { background: #edf3fa; }
.nav a:focus-visible, summary:focus-visible { outline: 3px solid #146bcc; outline-offset: 2px; }
.dropdown[open] > summary { background: #d4e5f5; }
section { margin-top: 40px; scroll-margin-top: 20px; }
@media (max-width: 480px) {
.dropdown { position: static; }
.panel { left: 0; width: 100%; }
}
</style>
</head>
<body>
<h1>강좌 메뉴</h1>
<nav class="nav" aria-label="학습 메뉴">
<a href="#intro">소개</a>
<details class="dropdown">
<summary>강좌</summary>
<ul class="panel">
<li><a href="#html">HTML 기초</a></li>
<li><a href="#css">CSS 기초</a></li>
<li><a href="#javascript">JavaScript 기초</a></li>
</ul>
</details>
</nav>
<main>
<section id="intro"><h2>소개</h2><p>상위 메뉴를 눌러 하위 링크를 펼쳐 보세요.</p></section>
<section id="html"><h2>HTML 기초</h2><p>문서 구조와 요소를 학습합니다.</p></section>
<section id="css"><h2>CSS 기초</h2><p>색과 배치를 학습합니다.</p></section>
<section id="javascript"><h2>JavaScript 기초</h2><p>페이지의 동작을 학습합니다.</p></section>
</main>
</body>
</html>
처음에는 “소개”와 “강좌”만 보입니다. 강좌를 누르면 하위 링크 세 개가 메뉴 아래에 겹쳐 표시됩니다. 같은 summary를 다시 누르면 닫힙니다. details에 open 속성을 미리 넣으면 처음부터 열린 상태로 시작하므로, 닫힌 상태를 기본으로 하려면 open을 넣지 않습니다.
하위 메뉴의 위치·너비·겹침 조절하기
dropdown의 position: relative는 하위 panel의 위치 기준을 만듭니다. panel에 absolute와 top: 100%, left: 0을 주어 넓은 화면에서 summary 바로 아래에서 시작하도록 했습니다. 목록은 일반 흐름에서 빠지므로 열려도 본문 전체를 아래로 밀지 않습니다. 펼쳐진 목록이 본문을 잠시 가리는 것이 싫다면 absolute를 제거해 아래 내용이 밀리는 구성을 선택할 수도 있습니다.
panel의 너비는 기본 250px이지만 화면보다 커지지 않도록 calc와 min으로 제한했습니다. 480px 이하에서는 dropdown을 static으로 바꾸어 nav를 위치 기준으로 사용하고, 하위 목록을 내비게이션 전체 너비로 펼칩니다. 예제에서는 드롭다운을 왼쪽 가까이에 두었습니다. 실제 사이트에서 오른쪽 끝에 배치한다면 left: auto와 right: 0으로 오른쪽 끝을 맞추거나 화면 경계 안에 들어오는 다른 배치를 검토해야 합니다. 메뉴 위치가 여러 곳으로 움직이는 복잡한 배치에서는 단순한 최대 너비만으로 모든 경계 문제를 해결할 수는 없습니다.
z-index는 같은 쌓임 맥락 안에서 메뉴를 앞쪽에 놓는 데 사용합니다. 부모의 overflow: hidden에 의해 잘리면 z-index만 크게 해도 영역 밖을 표시할 수 없습니다. 메뉴를 감싼 요소에 불필요한 숨김·스크롤 설정이 있는지 확인하세요. summary와 panel 사이에 마우스가 지나가야 하는 빈 간격을 만들지 않는 것도 중요합니다.
키보드·모바일과 자동 닫힘의 범위 확인하기
Tab 키로 소개 링크를 지나 강좌 summary에 초점을 둡니다. Space 또는 Enter로 펼친 뒤 Tab으로 하위 링크에 이동하고 Enter로 링크를 실행할 수 있는지 확인합니다. 닫힌 상태에서는 하위 링크가 화면에 표시되지 않고 탭 순서에서도 제외되어야 합니다. 마우스 없이도 현재 초점의 테두리가 보이도록 focus-visible을 유지했습니다.
좁은 창에서도 summary를 눌러 열기·닫기가 가능한지, 하위 링크가 화면 밖으로 나가지 않는지 확인합니다. 이 예제는 summary를 다시 조작해 닫는 기본 구조입니다. 메뉴 바깥 클릭, 링크 선택 후 자동 닫기, Escape로 닫고 초점을 돌려놓기까지 구현한 코드는 아닙니다. 그런 동작이나 여러 하위 메뉴 간의 복잡한 제어가 필요하면 JavaScript로 상태와 초점을 함께 관리하고 실제 입력 환경에서 검토해야 합니다.
hover만으로 보이게 하는 기존 방식을 사용할 때도 키보드 초점과 터치 사용을 함께 고려해야 합니다. focus-within을 추가하면 초점이 안에 머무는 동안 표시할 수 있지만, 클릭 토글·Escape 처리·바깥 클릭 닫기를 모두 대신하지는 않습니다. 단순한 펼치기 예제와 완성된 애플리케이션 메뉴의 동작 범위를 구분하는 것이 좋습니다.
기본 펼치기 동작은 MDN의 details 요소 설명, 사이트 내비게이션과 menu 역할의 구분은 W3C의 펼치기 내비게이션 안내를 참고할 수 있습니다. W3C 예제의 추가 키보드 동작은 별도 스크립트로 구현된 것이며 위의 기본 예제에 자동으로 포함되지는 않습니다.




