안녕하세요! 웹스토리보이입니다 😊
이번 시간은 가로 메뉴 스크립트 세 번째 유형을 함께 만들어보겠습니다!
이번 유형의 가장 큰 특징은, 마우스를 올렸을 때 서브메뉴 전체의 배경이 함께 나오는 구조입니다. 이전 유형 2에서는 서브 메뉴만 나왔지만, 이번엔 서브 메뉴를 감싸는 전체 배경까지 함께 나타나는 방식이죠.
이런 형태는 실무에서도 정말 자주 쓰이는 메뉴 구조예요. 특히 다양한 콘텐츠가 들어가는 복잡한 메뉴나, 메가 메뉴(Mega Menu) 형태에서도 자주 활용되기 때문에 실전에서도 써먹기 좋은 유형입니다. 물론 시험을 위한 연습이지만, 이번 유형은 실무에서도 강력하게 활용되는 구조이니 꼭 제대로 익혀두시면 앞으로도 큰 도움이 될 거예요! 그럼 오늘도 같이 차근차근 만들어볼까요? 렛츠 기릿! 💪😃
미리보기를 확인하시면 서브 메뉴가 전체 영역을 차지하는 메뉴 유형입니다. 메뉴가 헤더 밑 부분으로 위치해야 하고, 전체 영역은 헤더의 가로 값과 동일해야 하는 특징이 있습니다. 우선은 A-1 레이아웃 소스를 가져와서 작업을 해보겠습니다.
1<body>
2 <div id="wrap">
3 <div id="header">
4 <div class="logo"></div>
5 <nav class="nav"></nav>
6 </div>
7 <!-- //header -->
8
9 <div id="slider">
10 </div>
11 <!-- //slider -->
12
13 <div id="contents">
14 <div class="content1"></div>
15 <div class="content2"></div>
16 <div class="content3"></div>
17 </div>
18 <!-- //contents -->
19
20 <div id="footer">
21 <div class="footer1"></div>
22 <div class="footer2"></div>
23 <div class="footer3"></div>
24 </div>
25 <!-- //footer -->
26 </div>
27 <!-- //wrap -->
28</body>
1* {
2 margin: 0;
3 padding: 0;
4}
5li {
6 list-style: none;
7}
8a {
9 text-decoration: none;
10 color: #000;
11}
12#wrap {
13 width: 1200px;
14 margin: 0 auto;
15}
16#header {
17 width: 100%;
18 display: flex;
19}
20#header .logo {
21 width: 20%;
22 height: 100px;
23 background-color: #efefef;
24}
25#header .nav {
26 width: 80%;
27 background-color: #e3e3e3;
28}
29#slider {
30 width: 100%;
31 height: 300px;
32 background-color: #d9d9d9;
33}
34#contents {
35 width: 100%;
36 display: flex;
37}
38#contents .content1 {
39 width: 33.3333%;
40 height: 200px;
41 background-color: #d1d1d1;
42}
43#contents .content2 {
44 width: 33.3333%;
45 height: 200px;
46 background-color: #c7c7c7;
47}
48#contents .content3 {
49 width: 33.3333%;
50 height: 200px;
51 background-color: #bcbcbc;
52}
53#footer {
54 width: 100%;
55 display: flex;
56}
57#footer .footer1 {
58 width: 20%;
59 height: 100px;
60 background-color: #b1b1b1;
61}
62#footer .footer2 {
63 width: 60%;
64 height: 100px;
65 background-color: #a3a3a3;
66}
67#footer .footer3 {
68 width: 20%;
69 height: 100px;
70 background-color: #9d9d9d;
71}
메뉴 코드는 기본의 유형과 동일하게 작업을 할 것이고, 서브 메뉴에는 submenu 클래스를 작업하였습니다. .nav > ul > li안에 ul > li구조가 있는 형태입니다.
1<nav class="nav">
2 <ul>
3 <li>
4 <a href="#">메뉴1</a>
5 <ul class="submenu">
6 <li><a href="#">서브메뉴1-1</a></li>
7 <li><a href="#">서브메뉴1-2</a></li>
8 <li><a href="#">서브메뉴1-3</a></li>
9 <li><a href="#">서브메뉴1-4</a></li>
10 </ul>
11 </li>
12 <li>
13 <a href="#">메뉴2</a>
14 <ul class="submenu">
15 <li><a href="#">서브메뉴2-1</a></li>
16 <li><a href="#">서브메뉴2-2</a></li>
17 <li><a href="#">서브메뉴2-3</a></li>
18 <li><a href="#">서브메뉴2-4</a></li>
19 </ul>
20 </li>
21 <li>
22 <a href="#">메뉴3</a>
23 <ul class="submenu">
24 <li><a href="#">서브메뉴3-1</a></li>
25 <li><a href="#">서브메뉴3-2</a></li>
26 <li><a href="#">서브메뉴3-3</a></li>
27 <li><a href="#">서브메뉴3-4</a></li>
28 </ul>
29 </li>
30 <li>
31 <a href="#">메뉴4</a>
32 <ul class="submenu">
33 <li><a href="#">서브메뉴4-1</a></li>
34 <li><a href="#">서브메뉴4-2</a></li>
35 <li><a href="#">서브메뉴4-3</a></li>
36 <li><a href="#">서브메뉴4-4</a></li>
37 </ul>
38 </li>
39 </ul>
40</nav>
nav의 위치는 display: flex;와 justify-content: right;를 이용하여 오른쪽 하단으로 위치를 설정했습니다. 전체 영역의 배경이 필요하기 때문에 이것은 header영역에 가상요소를 만들어 클래스 on을 붙이면 나오도록 설정했습니다. 메뉴에 마우스 오버를 하면 서브 메뉴도 나오고 가상 요소 전체 배경도 나오게 작업할 것입니다. 스크립트를 작업하기 전에 CSS를 완벽하게 하고 넘어가야 합니다.
1/* nav */
2#header {
3 position: relative;
4}
5#header::after {
6 content: '';
7 width: 100%;
8 height: 0px;
9 background-color: #808080;
10 position: absolute;
11 left: 0;
12 top: 100px;
13 z-index: 1;
14 transition: all 400ms;
15}
16#header.on::after {
17 height: 155px;
18}
19.nav {
20 z-index: 1000;
21}
22.nav > ul {
23 display: flex;
24 justify-content: right;
25 margin-top: 61px;
26}
27.nav > ul > li {
28 position: relative;
29}
30.nav > ul > li > a {
31 display: inline-block;
32 padding: 10px 50px;
33 background-color: #b0b0b0;
34}
35.nav > ul > li > a:hover {
36 background-color: #696969;
37}
38.nav > ul > li > ul {
39 position: absolute;
40 left: 0;
41 top: 39px;
42 width: 100%;
43 text-align: center;
44 display: none;
45}
46.nav > ul > li > ul > li > a {
47 display: inline-block;
48 padding: 10px;
49 width: 100%;
50 box-sizing: border-box;
51}
52.nav > ul > li > ul > li > a:hover {
53 background-color: #8f8f8f;
54}
코드는 문서가 모두 로드된 뒤에 실행되도록 $(function()) 구문 안에서 시작됩니다.
이 구조는 jQuery에서 자주 사용하는 기본 패턴으로, HTML이 다 불러와지고 나면 그때부터 안의 코드를 실행해달라는 뜻이에요. 이제 본격적으로 메뉴 동작을 설정해봅니다.
먼저 .nav > ul > li — 즉, 각 메뉴 항목에 마우스를 올렸을 때 실행되는 동작을 지정해줄게요. 마우스를 올리면 .nav > ul > li > ul 이라는 서브 메뉴 전체를 선택해서 slideDown()으로 펼쳐줍니다. 그 전에 .stop()을 함께 사용하는 이유는, 빠르게 마우스를 왔다갔다 했을 때 애니메이션이 중첩돼서 꼬이지 않도록 기존 동작을 멈춰주기 위해서예요. 그리고 (900)이라는 값은 0.9초 동안 부드럽게 내려오라는 의미입니다. 이와 동시에 #header에 on 클래스를 추가해주는데요, 이 클래스는 CSS에서 ::after 가상요소에 배경을 보여주는 역할을 합니다. 즉, 메뉴에 마우스를 올리면 서브 메뉴도 내려오고, 배경도 함께 나타나는 구조가 되는 거죠. 이제 마우스를 떼면 어떻게 될까요?
다시 .nav > ul > li에 mouseout 이벤트를 지정해서, 서브 메뉴는 slideUp(100)으로 빠르게 닫아주고, #header에 추가했던 on 클래스도 removeClass()로 제거해줍니다. 이렇게 하면 배경도 자연스럽게 사라지게 됩니다.
1<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
1$(function(){
2 $(".nav > ul > li").mouseover(function(){
3 $(".nav > ul > li > ul").stop().slideDown(900);
4 $("#header").addClass("on");
5 });
6
7 $(".nav > ul > li").mouseout(function(){
8 $(".nav > ul > li > ul").stop().slideUp(100);
9 $("#header").removeClass("on");
10 });
11})
이 코드는 페이지가 완전히 로드된 후에 실행됩니다. 먼저, .nav > ul이라는 메뉴 전체 리스트를 선택해서 navList라는 변수에 저장하고, 그 영역에 mouseover와 mouseout 이벤트를 각각 등록합니다. 마우스를 메뉴 위에 올리면, navList 안에 있는 모든 .submenu 요소들을 선택해서 forEach()로 하나씩 꺼내며, 각 서브 메뉴의 style.height 값을 "155px"로 설정해 서브 메뉴가 펼쳐지도록 합니다.
이와 동시에, #header 요소에 on 클래스를 추가하여 CSS에서 정의한 가상 요소 배경이 나타나도록 설정합니다. 반대로 마우스를 메뉴에서 떼면 mouseout 이벤트가 실행되는데, 앞서 선택했던 .submenu들의 height를 "0px"로 되돌려 닫히게 만들고, #header에 추가했던 on 클래스를 제거하여 배경도 함께 사라지도록 처리합니다.
결과적으로 이 코드는 마우스를 올리면 모든 서브 메뉴와 배경이 함께 자연스럽게 펼쳐지고, 마우스를 떼면 모두 함께 닫히는 동작을 구현하는 스크립트입니다. 애니메이션 효과는 CSS의 transition 속성으로 부드럽게 처리됩니다.
1window.onload = function(){
2 let navList = document.querySelector(".nav > ul");
3
4 navList.addEventListener("mouseover", () => {
5 navList.querySelectorAll(".submenu").forEach(sub => {
6 sub.style.height = "155px";
7 });
8 document.getElementById("header").classList.add("on");
9 });
10
11 navList.addEventListener("mouseout", () => {
12 navList.querySelectorAll(".submenu").forEach(sub => {
13 sub.style.height = "0px";
14 });
15 document.getElementById("header").classList.remove("on");
16 });
17}
1/* 자바스크립트용 CSS */
2.nav > ul > li > ul {
3 display: block;
4 height: 0;
5 overflow: hidden;
6 transition: all 400ms;
7}
::after
: 서브메뉴 배경을 만들어주는 핵심.addClass("on")
→ 선택한 요소에 클래스를 추가합니다..removeClass("on")
→ 선택한 요소에서 지정한 클래스를 제거합니다..stop()
→ 현재 진행 중인 애니메이션을 멈추고 새로운 애니메이션을 실행합니다..slideDown(300)
/ .slideUp(300)
→ 요소를 부드럽게 열고 닫는 효과를 줍니다. 괄호 안의 숫자(밀리초)는 애니메이션의 속도입니다. 300
은 0.3초, 900
은 0.9초입니다.querySelector()
→ 하나의 요소만 선택할 때 사용합니다.querySelectorAll()
→ 여러 개의 요소를 한꺼번에 선택할 때 사용합니다.forEach()
→ querySelectorAll()
로 선택한 여러 요소에 하나씩 동작을 적용할 때 사용합니다.classList.add()
/ classList.remove()
→ 특정 요소에 클래스를 추가하거나 제거할 때 사용합니다.이번 유형은 단순히 메뉴를 보여주는 것을 넘어서 배경까지 함께 제어하는 고급 구조를 다뤘습니다. 이런 방식은 실제 실무 웹사이트에서도 자주 활용되는 만큼, 오늘의 실습은 단순 시험 대비를 넘어선 실전 코딩 경험이라고 생각하셔도 좋아요!
처음엔 선택자나 클래스 제어가 복잡해 보일 수 있지만, 구조의 흐름을 이해하고 나면 훨씬 쉽고 재밌게 느껴질 거예요. 지금은 따라만 해도 괜찮습니다. 자주 보고, 손으로 직접 코딩하면서 익히다 보면 어느 순간 ‘나도 할 수 있겠는데?’ 하는 자신감이 생길 거예요.
오늘도 끝까지 수고 많으셨습니다. 다음 시간엔 더 멋진 UI를 함께 만들어볼게요! 포기하지 마시고, 하나씩 천천히 함께 가봅시다! 당신의 성장을 항상 응원합니다. 😊💪