안녕하세요! 웹스토리보이입니다 😊
이번 시간은 가로 메뉴 스크립트 두 번째 유형을 함께 만들어보겠습니다! 먼저 오른쪽에 있는 미리보기 버튼을 눌러 완성된 모습을 한번 확인해보세요. 이번 메뉴는 첫 번째와 달리, 마우스를 올리면 모든 서브메뉴가 한 번에 보여지는 형태입니다.
첫 번째는 해당 항목만 서브메뉴가 열리는 구조였다면, 두 번째는 전체 서브메뉴가 동시에 열리는 구조예요. 스크립트 차이는 크지 않지만, 구조와 CSS가 조금 다르기 때문에 당황하지 않고 차근차근 진행하는 게 중요합니다. 특히 시험장에서는 스크립트보다 CSS 위치와 구조가 더 중요하게 작용하니, CSS를 먼저 정확하게 셋팅하고 넘어가는 습관을 들이시는 걸 추천드려요! 그럼 이번에도 하나씩 같이 만들어보면서 실력을 쌓아볼까요? 렛츠 기릿! 💪🥹
미리보기 화면을 확인해 보시면 메뉴에 마우스를 오버하면 서브 메뉴가 나오는 구조입니다. 우선 이 유형을 만들어 보기 전에 A-1 레이아웃 유형의 소스를 가져와서 메뉴 위치와 CSS를 먼저 작업하겠습니다. 스크립트를 작업하기 전에 CSS를 먼저 셋팅하는 것이 가장 중요합니다. 레이아웃을 공부를 하지 않았다면 레이아웃 유형을 꼭 공부하고 오셔야 합니다.
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}
여기까지 셋팅이 완료되었다면, 메뉴 레이아웃을 작업해보겠습니다. 메뉴 레이아웃은 li안에 li가 들어간 구조입니다. 이렇게 작업하면 구조가 깨지기 때문에 두번째 ul은 position: absolute를 이용하여 절대적인 위치값을 설정하였고, 부모 박스 li 속성에 position: relative;를 설정하였습니다. 또한 li 안에 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>
1/* nav */
2.nav > ul {
3 display: flex;
4 justify-content: right;
5 margin-top: 30px;
6}
7.nav > ul > li {
8 position: relative;
9}
10.nav > ul > li > a {
11 display: inline-block;
12 padding: 10px 50px;
13 background-color: #b0b0b0;
14}
15.nav > ul > li > a:hover {
16 background-color: #696969;
17}
18.nav > ul > li > ul {
19 position: absolute;
20 left: 0;
21 top: 38px;
22 width: 100%;
23 text-align: center;
24 display: none;
25}
26.nav > ul > li > ul > li > a {
27 display: inline-block;
28 padding: 10px;
29 background-color: #c1c1c1;
30 width: 100%;
31 box-sizing: border-box;
32}
33.nav > ul > li > ul > li > a:hover {
34 background-color: #8f8f8f;
35}
36/* 자바스크립트 CSS */
37.nav > ul > li > ul {
38 display: block;
39 height: 0;
40 overflow: hidden;
41 transition: all 600ms;
42}
제이쿼리를 작업하기 전에는 반드시 제이쿼리 라이브러리 파일을 연동하겠습니다.
1<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
이번에도 메뉴 유형 1과 마찬가지로 먼저 li 선택자를 설정해줄게요. $(".nav > ul > li")
그리고 여기에 마우스 오버 이벤트인 mouseenter를 추가하고, 모든 서브 메뉴(.nav > ul > li > ul)를 한꺼번에 열어줄 수 있도록 slideDown() 애니메이션을 사용하면 됩니다. 여기서 중요한 차이점이 있어요!
유형 1에서는 $(this)를 사용했죠? → 그래서 내가 마우스를 올린 해당 메뉴만 서브 메뉴가 나왔습니다. 하지만 지금은 $(this)를 쓰지 않고 .nav > ul > li > ul을 직접 선택합니다. → 이렇게 하면 모든 서브 메뉴가 동시에 열리게 됩니다.
바로 이 부분이 메뉴 유형 1과 유형 2의 가장 큰 차이점이에요. 선택자를 어디에 어떻게 쓰느냐에 따라 전체가 열릴지, 하나만 열릴지가 달라지는 거죠! mouseout 이벤트도 같은 방식으로 설정해주시면 됩니다. 그리고 꼭 넣어줘야 하는 부분이 하나 있어요 — 바로 .stop()입니다!
이걸 왜 쓰냐면요, 마우스를 빠르게 오버하거나 움직일 때, 애니메이션이 아직 끝나지 않았는데 또 새로운 애니메이션이 실행되면 버벅이거나 이상하게 작동할 수 있어요. 이때 .stop()을 사용하면 지금 진행 중인 애니메이션을 멈추고 새로운 명령만 실행하게 만들어서 불필요한 애니메이션 중첩을 방지할 수 있어요. 그래서 더 자연스럽고 안정적으로 작동하게 됩니다.
1$(function(){
2 $(".nav > ul > li").mouseover(function(){
3 $(".nav > ul > li > ul").stop().slideDown(200);
4 });
5
6 $(".nav > ul > li").mouseout(function(){
7 $(".nav > ul > li > ul").stop().slideUp(200);
8 });
9})
먼저 navList라는 변수를 만들어서 메뉴 전체 영역인 .nav > ul을 선택해줄게요. 그다음, 마우스를 ul에 올렸을 때 ul의 자식들인 .submenu를 찾아서 모두 동시에 열어주도록 height 값을 152px로 설정합니다.
서브 메뉴가 여러 개이기 때문에 querySelectorAll(".submenu")로 전부 선택한 뒤, forEach()를 사용해서 반복 처리해줍니다. 자바스크립트는 제이쿼리처럼 .slideDown() 같은 애니메이션 기능이 없어요. 그래서 부드러운 전환 효과는 CSS에서 따로 설정해줘야 합니다.
마우스를 뗐을 때(mouseout)도 같은 방식으로 처리하되, 이번엔 height 값을 0으로 바꿔주면 자연스럽게 닫히는 애니메이션이 적용됩니다. 확실히 제이쿼리보다 직접 처리해줘야 할 부분이 조금 더 많긴 하지만, 애니메이션의 원리나 흐름은 거의 동일합니다. 이 방식에 익숙해지면 나중에 더 다양한 동적 기능도 쉽게 구현할 수 있어요!
1window.onload = function(){
2 let navList = document.querySelector(".nav > ul");
3
4 navList.addEventListener("mouseover", function(){
5 navList.querySelectorAll(".submenu").forEach(sub => {
6 sub.style.height = "155px";
7 });
8 });
9 navList.addEventListener("mouseout", function(){
10 navList.querySelectorAll(".submenu").forEach(sub => {
11 sub.style.height = "0px";
12 });
13 });
14}
1/* 자바스크립트 CSS */
2.nav > ul > li > ul {
3 display: block;
4 height: 0;
5 overflow: hidden;
6 transition: all 600ms;
7}
>
기호는 바로 아래의 직계 자식만 선택할 때 사용.nav > ul > li
→ 정확하게 단계별 요소만 선택.nav ul li
→ 중첩된 모든 하위 요소까지 선택되어 의도치 않게 적용될 수 있음>
기호를 써서 정확한 선택자 사용이 중요처음에는 선택자도 어렵고, 제이쿼리와 자바스크립트 차이도 헷갈릴 수 있어요. 하지만 지금 여러분은 단순히 따라 치는 걸 넘어, 어떤 구조가 왜 필요한지, 무엇을 조심해야 하는지까지 배워가고 있습니다.
🌱 오늘 배운 것을 한 번 더 복습해보고, “왜 이렇게 써야 하는 걸까?” 하고 질문해보세요. 그 고민이 쌓이면 시험장에서의 실수는 점점 줄어들고, 진짜 실무에서도 통하는 개발자로 성장하게 됩니다.
무엇보다 중요한 건, 지금 포기하지 않고 끝까지 따라와 주신 여러분의 꾸준함이에요. 작은 성취가 쌓이면 어느 순간 큰 자신감이 됩니다. 수고 많으셨습니다! 다음 시간에도 함께 성장해봐요 😊 당신의 코딩 여정, 제가 계속 함께 하겠습니다! 화이팅입니다! 💪🚀