안녕하세요! 웹스토리보이입니다 😊
이번 시간에는 네 번째 메뉴 유형, 바로 세로형 메뉴를 함께 만들어보겠습니다.
이번 메뉴는 사이드 메뉴가 있는 레이아웃에서 자주 사용되는 구조로, 가로형과는 조금 다른 느낌의 인터페이스를 경험하실 수 있어요. PDF를 살펴보면 이 메뉴는 정적인 레이아웃뿐 아니라, 반응형 레이아웃에서도 자주 사용되는 걸 볼 수 있는데요, 이번에는 그중에서도 조금 더 난이도가 있을 수 있는 반응형 레이아웃 환경에서 작업을 진행해보겠습니다.
사실 메뉴 유형 1, 2, 3번에서 사용된 원리와 이번 세로형 메뉴의 원리는 거의 동일합니다. 다만 가로와 세로 레이아웃에 따라 약간의 구조적 차이가 생기기 때문에 이 부분을 함께 짚어보면서 비교해보시면 훨씬 이해가 쉬울 거예요. 이번 시간은 복습하는 마음으로 천천히 따라오시면 됩니다. 그럼 오늘도 새로운 유형으로 연습해볼까요? 렛츠 기릿! 😆💪
이번에는 D-1 유형 레이아웃에 메뉴 유형을 작업을 해보겠습니다. 기본적인 코드는 그대로 복사하셔서 사용하셔도 됩니다.
1<body>
2 <div id="wrap">
3 <aside id="aside">
4 <h1></h1>
5 <nav></nav>
6 </aside>
7 <!-- //aside -->
8
9 <main id="main">
10 <article id="slider"></article>
11 <article id="link"></article>
12 <section id="contents">
13 <div class="content1"></div>
14 <div class="content2"></div>
15 </section>
16 </main>
17 <!-- //main -->
18
19 <footer id="footer">
20 <div class="footer1"></div>
21 <div class="footer2">
22 <div class="footer2-1"></div>
23 <div class="footer2-2"></div>
24 </div>
25 <div class="footer3"></div>
26 </footer>
27 <!-- //footer -->
28 </div>
29 <!-- //wrap -->
30</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: 100%;
14 display: flex;
15 flex-wrap: wrap;
16}
17#aside {
18 width: 200px;
19}
20#aside h1 {
21 width: 100%;
22 height: 100px;
23 background-color: #efefef;
24}
25#aside nav {
26 width: 100%;
27 height: 700px;
28 background-color: #e3e3e3;
29}
30#main {
31 width: calc(100% - 200px);
32}
33#slider {
34 width: 100%;
35 height: 400px;
36 background-color: #d9d9d9;
37}
38#link {
39 width: 100%;
40 height: 150px;
41 background-color: #d1d1d1;
42}
43#contents {
44 width: 100%;
45 display: flex;
46}
47#contents .content1 {
48 width: 50%;
49 height: 250px;
50 background-color: #c7c7c7;
51}
52#contents .content2 {
53 width: 50%;
54 height: 250px;
55 background-color: #bcbcbc;
56}
57#footer {
58 width: 100%;
59 display: flex;
60}
61#footer .footer1 {
62 width: 20%;
63 height: 120px;
64 background-color: #b1b1b1;
65}
66#footer .footer2 {
67 width: 60%;
68}
69#footer .footer2 .footer2-1 {
70 width: 100%;
71 height: 60px;
72 background-color: #a3a3a3;
73}
74#footer .footer2 .footer2-2 {
75 width: 100%;
76 height: 60px;
77 background-color: #9d9d9d;
78}
79#footer .footer3 {
80 width: 20%;
81 height: 120px;
82 background-color: #929292;
83}
메뉴 코드를 추가하고 CSS를 설정하겠습니다. CSS는 기존보다 조금 더 간단합니다. 우선 서브 메뉴는 잠시 숨겨놓겠습니다.
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 > li > a {
3 display: block;
4 padding: 10px;
5 background-color: #ccc;
6 text-align: center;
7}
8.nav > ul > li > a:hover {
9 background-color: #9c9c9c;
10}
11.nav > ul > li > ul {
12 display: none;
13}
14.nav > ul > li > ul > li > a {
15 display: block;
16 padding: 10px;
17 text-align: center;
18}
19.nav > ul > li > ul > li > a:hover {
20 background-color: #c0c0c0;
21}
먼저 <script> 태그로 외부 제이쿼리 라이브러리를 불러왔습니다. 이렇게 해야 제이쿼리 문법을 사용할 수 있습니다.
이제 실제 동작을 살펴볼게요. .nav > ul > li는 메뉴의 각 항목들을 선택하는 선택자입니다. 이 항목들에 mouseover 이벤트를 걸어주고, 해당 항목 안에서 .submenu라는 클래스를 가진 서브메뉴를 찾아서 .slideDown()을 실행합니다. 이 메서드는 서브메뉴를 아래로 펼치는 애니메이션을 만들어주는 역할을 합니다.
그 전에 .stop()을 사용하는 이유는 애니메이션이 여러 번 겹쳐서 실행되는 걸 막기 위해서예요. 예를 들어 마우스를 빠르게 왔다갔다 하면 slideDown()이 계속 누적되는데, .stop()을 써주면 이전 애니메이션을 멈추고 새로운 동작만 실행하게 됩니다.
마우스를 떼면 mouseout 이벤트가 실행되고, 이번에는 .slideUp() 메서드가 작동해서 서브메뉴가 위로 접히듯 사라지게 됩니다. 간단하게 말해서, 마우스를 올리면 slideDown(), 내리면 slideUp()으로 서브메뉴를 부드럽게 열고 닫는 구조입니다. 코드는 짧지만, 이 안에 선택자 지정, 이벤트 처리, 애니메이션, 그리고 충돌 방지를 위한 .stop()까지 꼭 알아야 할 핵심 기능들이 잘 담겨 있어요.
1<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
2<script>
3 $(".nav > ul > li").mouseover(function(){
4 $(this).find(".submenu").stop().slideDown();
5 });
6
7 $(".nav > ul > li").mouseout(function(){
8 $(this).find(".submenu").stop().slideUp();
9 });
10</script>
먼저, window.onload를 사용해서 웹페이지의 모든 요소가 완전히 로드된 뒤에 아래의 스크립트가 실행되도록 했습니다. 이렇게 하면 HTML이 아직 다 불러와지기 전에 스크립트가 먼저 실행되는 걸 방지할 수 있어요.
그다음은 메뉴 항목을 선택해줘야겠죠? document.querySelectorAll(".nav > ul > li") 이 코드는 메뉴의 1차 항목들, 즉 li 요소들을 모두 찾아줍니다. 여러 개니까 querySelectorAll을 사용한 거예요. 그리고 나서 forEach 문을 써서 각 메뉴 항목 하나하나에 이벤트를 걸어줍니다. 마우스를 올렸을 때 mouseover 이벤트가 실행되고, 그 안에서 this.querySelector(".submenu")를 사용해 해당 메뉴 항목의 서브메뉴를 찾습니다. 그리고 그 서브메뉴의 style.height를 "155px"로 설정해줍니다. 그러면 서브메뉴가 펼쳐지듯이 나타나겠죠?
반대로 마우스를 떼면, 즉 mouseout 이벤트가 발생하면 같은 방식으로 style.height를 "0px"로 바꿔주면서 서브메뉴를 다시 접어줍니다. 여기서 부드럽게 열리고 닫히는 효과를 주기 위해서는 CSS에서 transition과 overflow: hidden 설정이 꼭 같이 들어가 있어야 한다는 점, 기억해주세요. 자바스크립트는 높이값만 조정해주는 거고, 애니메이션처럼 자연스럽게 보이는 건 CSS의 역할입니다.
1window.onload = function(){
2 var navList = document.querySelectorAll(".nav > ul > li");
3
4 navList.forEach(function(navItem) {
5 navItem.addEventListener("mouseover", function() {
6 this.querySelector(".submenu").style.height = "155px";
7 });
8 navItem.addEventListener("mouseout", function() {
9 this.querySelector(".submenu").style.height = "0px";
10 });
11 });
12};
1/* 자바스크립트용 CSS */
2.nav > ul > li > ul {
3 display: block;
4 height: 0;
5 overflow: hidden;
6 transition: all 400ms;
7}
이번 시간에는 세로형 메뉴, 특히 반응형 레이아웃 속 사이드 메뉴를 구현해보았습니다. 그동안의 가로형 메뉴와는 구조는 다르지만, 내부 동작 원리는 동일하다는 것을 느끼셨을 거예요. 처음에는 방향이 바뀌는 것만으로도 어렵게 느껴질 수 있지만, 하나하나 비교하면서 따라가다 보면 레이아웃이 어떻게 바뀌더라도 스크립트의 핵심 흐름은 같다는 것을 이해하게 될 겁니다.
이제 중요한 건 반복 연습과 흐름 파악이에요. 스크립트를 단순히 외우는 게 아니라, "왜 이렇게 작동하지?" "무엇을 선택해서 어떤 행동을 시키는지" 이런 논리적인 흐름을 이해하면 어떤 유형이 나와도 두려울 게 없어요! 혹시 오늘도 이해가 어려웠다면, 걱정하지 마세요. 처음에는 누구나 헷갈리고, 따라만 해도 충분히 성장하고 있는 겁니다.
매번 하나씩 쌓아가면서 여러분만의 실무 감각을 키워보세요! 다음 시간엔 더 흥미롭고 실전에서 바로 쓸 수 있는 UI로 함께 연습해보겠습니다. 오늘도 정말 수고 많으셨습니다. 포기하지 말고 끝까지! 여러분의 도전을 언제나 응원합니다 😊💪