문제 정의
| 항목 | 설명 |
|---|---|
| 현재 동작 | 모바일 햄버거 메뉴 버튼을 눌러도 메뉴가 안 보임 |
| 문제 상황 | 메뉴와 배경을 토글하는 동작이 구현되어 있지 않음 |
| 사용자 기대 | 버튼 클릭 시 메뉴와 어두운 배경이 함께 나타나야 함 |
| UX 문제 | 메뉴가 떠야 할 때 아무 반응이 없어 조작 불가능함 |
정답 코드 설명
.mobile-top-bar내부의 메뉴 영역에.active클래스를 토글함
어두운 배경도 함께.active를 붙여 노출
닫을 때는.active를 제거
JS 코드
$('.btn-toggle-mobile-menu').click(function () { $('.mobile-top-bar').toggleClass('active'); });
toggleClass('active'): 클릭할 때마다 클래스 추가/제거.mobile-top-bar에.active를 붙여 배경 및 메뉴 표시
CSS 코드 핵심
/* 초기 메뉴는 숨김 */
.mobile-top-bar .mobile-menu, .mobile-top-bar::before { display: none; }
/* 배경 요소 만들기 (가상 요소 사용) */
.mobile-top-bar.active::before { content: ""; position: fixed; inset: 0; background-color: rgba(0,0,0,0.5); z-index: 9; display: block; }
/* 메뉴 보이기 */
.mobile-top-bar.active .mobile-menu { display: block; position: fixed; right: 0; top: 0; width: 200px; height: 100%; background: white; z-index: 10; }
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 햄버거 버튼 있음 | O | O |
| 클릭 시 메뉴 노출 | X | O (.active로 제어) |
| 배경 어두운 효과 있음 | X | O (::before, rgba) 적용 |
| 메뉴 위치/스타일 설정됨 | X | O (position: fixed) 적용 |
핵심 정리
| 개념 | 설명 |
|---|---|
.toggleClass() | 클릭할 때마다 .active 추가/제거 |
::before | 배경을 어둡게 덮는 역할 (가상 요소) |
.mobile-menu | 실제 보이는 사이드 메뉴 영역 |
z-index | 배경과 메뉴 순서 조정 (배경 < 메뉴) |
position: fixed | 배경과 메뉴 모두 화면 고정 표시 |
한 줄 요약
클릭 시.active클래스를 활용해 메뉴와 배경을 함께 노출시키는 것이 이번 강의의 핵심이야.::before로 배경 처리하는 CSS 기법도 중요한 포인트!
문제
조건
- 우측에서 너비 300px 짜리
.mobile-side-bar__content엘리먼트가 나타남.mobile-side-bar__content의 높이는 100%- 배경은 흰색
정답
정답2(only css)
선생님 풀이영상
문제 정의
| 항목 | 설명 |
|---|---|
| 현재 동작 | 버튼 클릭 시 배경은 어두워지지만, 콘텐츠(메뉴창)는 보이지 않음 |
| 문제 상황 | .mobile-side-bar__content가 아직 스타일로 숨겨져 있음 |
| 사용자 기대 | 콘텐츠가 우측에서 슬라이드 되어 나오기를 기대함 |
| UX 목적 | 자연스럽고 직관적인 메뉴 등장 애니메이션 제공 |
목표 조건
.mobile-side-bar__content는 고정 위치,width: 300pxheight: 100%, background-color: white- 평소엔 오른쪽 바깥쪽
(right: -300px)- 메뉴 버튼 클릭 시
right: 0으로 이동
JS 코드
$('.btn-toggle-mobile-menu').click(function () { $('.mobile-top-bar').toggleClass('active'); });
- 역할:
.active클래스를 토글해서 CSS 전환 트리거- 나머지 처리는 CSS에서
.active상태를 감지하여 수행
핵심 CSS
.mobile-side-bar__content { position: fixed; top: 0; right: -300px; /* 처음엔 화면 밖 */ width: 300px; height: 100%; background-color: white; z-index: 10; transition: right 0.3s ease; }
.mobile-top-bar.active .mobile-side-bar__content { right: 0; /* 메뉴 등장 */ }
문제 vs 정답 비교
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 메뉴 콘텐츠 보임 | X | O (right: 0으로 등장) |
위치 고정 (position: fixed) | X | O |
애니메이션 효과 (transition) | X | O (right 값 변화) |
| UX 기대 충족 | X | O (우측에서 부드럽게 등장) |
핵심 정리
| 개념 | 설명 |
|---|---|
.mobile-side-bar__content | 실제 메뉴 콘텐츠 박스 |
right: -300px | 기본 상태 (숨김) |
right: 0 | 활성화 시 등장 위치 |
transition | 자연스러운 슬라이드 효과 부여 |
.mobile-top-bar.active | 클래스 기반 상태 전환 컨트롤 |
한 줄 요약
.mobile-side-bar__content는 right 값을 CSS로 조절하여 슬라이드 등장시키는 구조로 구현한다!
문제
조건
.mobile-side-bar__content의 자식으로.mobile-side-bar__head와.mobile-- - side-bar__body.mobile-side-bar__head의 자식으로 닫기 버튼- pc 화면에서 사이드바 숨기기
정답1
정답2(only css)
선생님 풀이영상
문제 요약
| 항목 | 설명 |
|---|---|
| 닫기 버튼 | 사이드바 안에 있고, 클릭 시 사이드바 닫힘 |
| 사이드바 구조 | .mobile-side-bar__content 내부에 .mobile-side-bar__head, .mobile-side-bar__body |
| PC에서 | 화면 너비가 넓으면 사이드바 자동 숨김 처리 필요 (미디어 쿼리 사용) |
HTML 구조 예시
<!-- 토글 버튼 -->
<div class="btn-toggle-mobile-side-bar">☰</div>
<!-- 모바일 사이드바 전체 -->
<div class="mobile-side-bar">
<div class="mobile-side-bar__content">
<div class="mobile-side-bar__head">
<div class="btn-close-mobile-side-bar">X</div>
</div>
<div class="mobile-side-bar__body">
<!-- 메뉴 내용 -->
</div>
/div>
/div>
CSS 코드 요약
/* 사이드바 기본 숨김 */
.mobile-side-bar { display: none; position: fixed; inset: 0; background-color: rgba(0, 0, 0, 0.5); z-index: 100; }
.mobile-side-bar.active { display: block; }
.mobile-side-bar__content { width: 300px; height: 100%; background-color: white; position: absolute; right: 0; top: 0; }
/* PC화면에서 사이드바 완전 숨김 */
@media (min-width: 1024px) { .mobile-side-bar { display: none !important; } }
JS 코드 설명(jQuery)
// 메뉴 열기 버튼 클릭 시
$('.btn-toggle-mobile-side-bar').click(function () { $('.mobile-side-bar').addClass('active'); });
// 닫기 버튼 클릭 시
$('.btn-close-mobile-side-bar').click(function () { $('.mobile-side-bar').removeClass('active'); });
핵심 흐름 정리
| 동작 | 대상 | 처리 방식 |
|---|---|---|
| 메뉴 열기 | .btn-toggle-mobile-side-bar 클릭 | .mobile-side-bar에 .active 추가 |
| 메뉴 닫기 | .btn-close-mobile-side-bar 클릭 | .mobile-side-bar에서 .active 제거 |
| PC에서 숨기기 | @media (min-width:1024px) | .mobile-side-bar { display: none !important; } |
시각적 요약
모바일
☰ ← 클릭 → 사이드바 등장 (X 버튼 포함)
X ← 클릭 → 사이드바 사라짐
PC
☰ 버튼, 사이드바 모두 숨김 (자동)
핵심 개념 요약
.active클래스를 통해 사이드바 ON/OFF를 제어- 닫기 버튼은
.removeClass('active')- PC에서는 미디어 쿼리로 강제 숨김 처리
- 구조는 head + body로 나뉘며 head 안에 닫기 버튼
문제
조건
- 3차 메뉴까지 생성
- 단계적 아이템 활성화
overflow-y-auto
문제 - 정답, 단계 1, BEM, 격리
문제 - 정답, 단계 2, 메뉴 마크업
문제 - 정답, 단계 3, not, only-child
문제 - 정답, 단계 4, 반투명 배경중첩
문제 - 정답, 단계 5, 아이템 클릭시 active 토글
문제 - 정답, 단계 6, n차 메뉴 아이템에도 이벤트
문제 - 정답, 단계 7, 클릭시 활성화된 형제 active 제거
문제 - 정답, 단계 8, 클릭시 활성화된 형제의 후손들에 active 제거
문제 - 정답, 단계 9, 활성된 아이템 클릭시, 해당 아이템의 후손에 active 제거
문제 - 정답, 단계 10, 모바일 메뉴 박스 끄고, 켜는 기능 구현
문제 - 정답, 단계 11, 모바일 메뉴 박스를 끌 때, 모든 active 제거
문제 - 정답, 단계 12, 기존소스에 병합, overflow-y-auto
선생님 풀이영상!
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 모바일 사이드 메뉴 구조가 설계되지 않음 |
| 문제 상황 | 메뉴 구조와 클래스 네이밍이 일관성 없음, 중복이나 충돌 가능성 있음 |
| 기대 동작 | 명확한 BEM 구조와 CSS 격리 구조 필요 |
| UI 설계 목적 | 유지보수와 확장성에 강한 구조로 작성되어야 함 |
정답 구조 설명
- BEM(Block Element Modifier) 방식으로 구조화
- 메뉴의 각 부분을 명확하게 분리하여 스타일 충돌 방지
.mobile-side-bar는 전체 모바일 메뉴 컨테이너.mobile-side-bar__content,.mobile-side-bar__head,.mobile-side-bar__body등으로 요소 분리
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 (BEM 방식) |
|---|---|---|
| 클래스 네이밍 | .sidebar, .content 등 | .mobile-side-bar, .mobile-side-bar__content 등 |
| 구조 분리 | 약함 | 강함 (헤드, 바디 명확 분리) |
| 유지보수 편의성 | 낮음 | 높음 |
| 격리/확장성 | 미흡 | 좋음 (컴포넌트 단위 설계) |
코드 해석
HTML
<!-- 모바일 사이드 바 전체 구조 -->
<div class="mobile-side-bar">
<!-- 사이드바 안의 콘텐츠 -->
<div class="mobile-side-bar__content">
<!-- 헤더: 닫기 버튼, 타이틀 등 -->
<div class="mobile-side-bar__head">
<!-- 닫기 버튼 자리 -->
</div>
<!-- 본문: 메뉴들 -->
<div class="mobile-side-bar__body">
<!-- 메뉴 아이템 -->
</div>
</div>
</div>
- 각 파트는 명확한 클래스 명으로 설계 → CSS/JS에서도 쉽게 접근 가능
핵심 정리표
| 개념 | 내용 |
|---|---|
| BEM 방식 설계 | Block__Element--Modifier 구조 사용 |
| 구조 분리 | 콘텐츠/헤더/바디를 각각 요소로 분리 |
| CSS 격리 | 각 컴포넌트의 영향 범위를 한정함 |
| 확장 가능성 | 메뉴 항목이 늘어나도 구조는 동일하게 유지 가능 |
한줄 요약
BEM 네이밍과 구조 분리는 모든 반응형 UI의 기본 뼈대! 확장성과 유지보수를 위해 이 단계는 꼭 탄탄하게 설계해야 함.
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 메뉴 항목이 단순 <div> 나열로 구성됨 |
| 문제 상황 | 2차, 3차 메뉴가 없어 계층적인 UI 설계 불가 |
| 기대 구조 | 메뉴를 계층 구조(1차 > 2차 > 3차)로 구성하고 클래스 구분 필요 |
| UI 목적 | 사용자에게 하위 메뉴 존재 여부를 구조적으로 알려주는 설계 필요 |
정답 구조 요약 (메뉴 마크업 작성)
- 각 메뉴 아이템을
menu-box > ul > li구조로 구성- li 안에 하위 메뉴가 존재하는 경우
.sub-menu-box로 감싸서 표현- 메뉴 단계 구분은 클래스나 DOM 깊이로 판단
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 메뉴 깊이 구조 | 없음 | 있음 (ul > li > .sub-menu-box) |
| 클래스 네이밍 | 일반적 | menu-box, sub-menu-box 명확함 |
| 계층 표현 | 불가능 | 가능 (HTML 구조적으로 표현) |
| 확장성 | 낮음 | 높음 (n차 메뉴까지 확장 가능) |
코드 해석
HTML
<div class="menu-box">
<ul>
<li>
1차 메뉴 A
<div class="sub-menu-box">
<ul>
<li>
2차 메뉴 A-1
<div class="sub-menu-box">
<ul>
<li>3차 메뉴 A-1-1</li>
<li>3차 메뉴 A-1-2</li>
</ul>
</div>
</li>
<li>2차 메뉴 A-2</li>
</ul>
</div>
</li>
<li>1차 메뉴 B</li>
</ul>
</div>
📌 핵심 구조 흐름:
menu-box>ul>li>.sub-menu-box>ul>li> ...
→ 1차 메뉴 아래에 2차, 2차 아래에 3차 메뉴를 중첩 구조로 표현
핵심 정리표
| 개념 | 설명 |
|---|---|
.menu-box | 전체 메뉴 컨테이너 |
.sub-menu-box | 하위 메뉴를 감싸는 박스 |
| 계층 구조 설계 | 하위 메뉴는 상위 메뉴 내부에 중첩 |
| HTML 중첩 구조 설계 | 단계별 메뉴를 <ul> > <li>로 구현 |
한줄 요약
메뉴를 다단계(n차)로 구성할 땐,.menu-box>.sub-menu-box구조로 계층을 명확히 나누는 마크업이 핵심
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 모든 메뉴 항목이 동일하게 표시됨 |
| 문제 상황 | 하위 메뉴가 있는지 없는지 시각적으로 구분되지 않음 |
| 기대 동작 | 하위 메뉴가 없는 메뉴 항목에는 > 화살표를 제거하거나 스타일 다르게 |
| UX 목적 | 사용자가 눌러도 하위 메뉴 없는 항목을 미리 구분 가능하도록 하기 |
정답 구조 요약 (:not, :only-child 활용)
- CSS 선택자
:not(:only-child)또는:has()를 활용하여
하위 메뉴가 있는 항목만 특정 스타일 적용
-불필요한 화살표, 여백 등을 제거 가능
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 하위 메뉴 여부 구분 | X | O (:not(:only-child) 사용) |
| UI 일관성 | 미흡 | 향상됨 (하위 메뉴 유무 구분 가능) |
| UX 최적화 | 낮음 | 높음 (사용자가 메뉴 구조 예측 가능) |
코드 해석
CSS
/* 하위 메뉴가 없는 li → 화살표 제거 */
.menu-box > ul > li:not(:has(.sub-menu-box)) { background-image: none; }
- 만약 :has() 선택자를 지원하지 않는 환경이라면 JS로 클래스 추가 처리해도 됨
.menu-box ul > li:only-child {
/* 단독 항목에만 스타일 적용 */
}
핵심 정리표
| 개념 | 설명 |
|---|---|
:only-child | 형제 요소가 없는 자식에게 스타일 적용 |
:not() | 특정 조건을 제외한 요소에 스타일 적용 |
:has() | 하위 요소 유무에 따라 스타일 제어 (CSS4) |
| 하위 메뉴 구분 목적 | 클릭해도 펼쳐지지 않는 항목은 시각적으로 구분 필요 |
한줄 요약
:not과:only-child를 활용하면 하위 메뉴 없는 항목을 시각적으로 구분하여 UX를 개선할 수 있음
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 메뉴를 클릭하면 하위 메뉴는 나타나지만, 계층 구조가 명확하지 않음 |
| 문제 상황 | 2차, 3차 메뉴가 중첩돼도 시각적으로 계층을 표현하지 못함 |
| 기대 동작 | 하위 메뉴가 열릴수록 점점 어두운 배경이 겹치며 계층 깊이 표현 |
| UI 목적 | 사용자에게 현재 메뉴 깊이를 자연스럽게 인식시켜주는 시각적 피드백 제공 |
정답 구조 요약
- 하위 메뉴가 열릴 때
.menu-bg같은 반투명한 배경 요소를 생성하거나 표시- 메뉴 계층이 깊어질수록 배경도 여러 겹으로 쌓이며 어두워지는 효과
position: absolute를 활용한z-index계층 배치
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 배경 중첩 효과 | X | O |
| 메뉴 계층 시각 구분 | 약함 | 강함 |
| UX 직관성 | 낮음 | 높음 |
스타일 계층 표현 (z-index) | 없음 | 적용됨 |
코드 해석
CSS
.menu-bg { position: absolute; inset: 0; background-color: rgba(0, 0, 0, 0.5); /* 반투명 검정 */ z-index: 10; /* 상위 메뉴보다 아래 */ }
.menu-bg가 메뉴 박스 바로 아래에 들어가며, 클릭 시마다 하나씩 추가되거나 스타일만 바뀌는 구조
핵심 정리표
| 개념 | 설명 |
|---|---|
| 배경 레이어 분리 | 메뉴 콘텐츠와 분리된 .menu-bg 사용 |
z-index 활용 | 메뉴 계층에 따라 배경이 겹치도록 처리 |
반투명 배경 (rgba) | 단계별 메뉴 깊이에 따라 어두운 레이어 중첩 가능 |
| UX 효과 | 메뉴가 안쪽으로 들어갈수록 자연스럽게 깊이감 표현 가능 |
한줄 요약
- 하위 메뉴 열릴 때 반투명 배경을 중첩시켜 계층의 깊이를 시각적으로 표현함으로써 사용자에게 더 직관적인 메뉴 구조를 제공할 수 있음.
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 메뉴 클릭 시 아무 반응 없음 |
| 문제 상황 | 하위 메뉴가 열리거나 닫히지 않음 → 사용자 상호작용 불가 |
| 기대 동작 | 메뉴 항목을 클릭하면 해당 항목이 .active 클래스를 얻고, 하위 메뉴 표시 |
| 목적 | 클릭 기반으로 하위 메뉴를 열고 닫는 아코디언 형태 인터랙션 구현 |
정답 동작 설명
- 메뉴 항목을 클릭하면 해당
<li>요소에.active클래스가 토글됨.active클래스가 있을 때만 하위 메뉴 표시 (CSS로 제어)jQuery .toggleClass()사용
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 클릭 반응 | 없음 | 있음 |
| 하위 메뉴 토글 | 불가 | 가능 |
| 클래스 상태 제어 | 없음 | .toggleClass('active') 사용 |
| 유저 상호작용 UX | 부족 | 개선됨 |
JS 코드 해석 (정답 기준)
$('.menu-box ul > li').click(function () { $(this).toggleClass('active'); });
- li를 클릭하면
.active클래스가 켜지거나 꺼짐- 해당 클래스가 있으면 CSS에서 하위 메뉴를 보여주도록 처리
CSS 제어 예시
.sub-menu-box { display: none; }
li.active > .sub-menu-box { display: block; }
.active상태일 때 하위 메뉴 열림- 비활성 상태면 닫힘
핵심 정리표
| 개념 | 설명 |
|---|---|
.toggleClass('active') | 클릭할 때마다 클래스 on/off |
.active | 하위 메뉴를 보여주는 기준 |
.sub-menu-box | 하위 메뉴를 감싸는 요소 |
| 클릭 기반 토글 UX | 기본 아코디언 구조 형성 시작점 |
한줄 요약
메뉴 항목을 클릭하면.active클래스를 토글하여 하위 메뉴를 보여주거나 숨기는 아코디언 메뉴의 핵심 로직을 구현함.
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 1차 메뉴만 클릭 이벤트 적용됨 |
| 문제 상황 | 2차, 3차 메뉴 등 하위 메뉴 항목 클릭 시 동작하지 않음 |
| 기대 동작 | 메뉴 항목이라면 몇 차든 모두 클릭 시 .active 토글 작동 |
| 목적 | 메뉴 전체에 동일한 동작 로직을 적용하여 계층 메뉴 일관성 확보 |
정답 동작 설명
모든<li>에 대해 이벤트를 걸기 위해$('.menu-box li')로 선택 범위 확장
- 클릭된 메뉴 항목(li)에
.active토글- 구조 상 1차든 2차든, 몇 차든 상관없이 적용됨
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 클릭 이벤트 범위 | $('.menu-box > ul > li') | $('.menu-box li') |
| 하위 메뉴 반응 여부 | X | O |
| 동작 일관성 | 낮음 | 높음 |
| 재사용성/확장성 | 불편함 | 높음 (n차 메뉴도 자동 적용됨) |
JS 코드 해석
$('.menu-box li').click(function (e) { $(this).toggleClass('active'); });
- 클릭된
li요소에만.active클래스가 토글됨.menu-box li선택자를 사용해 모든 단계의 메뉴를 포함시킴
추가 보완 (이벤트 전파 방지 필요 여부)
- 현재는 상위 메뉴도 클릭 이벤트를 가지고 있어 중첩된 하위 메뉴 클릭 시 이벤트 전파 문제 발생 가능
- 이 경우
e.stopPropagation()도입 예정 (→ 이후 단계)
핵심 정리표
| 개념 | 설명 |
|---|---|
$('.menu-box li') | 전체 메뉴 계층 선택자 |
.toggleClass('active') | 클릭 시 클래스 on/off |
| n차 메뉴 호환성 | 1~3차 전부 동일 로직 적용 |
| 이벤트 전파 고려 | 추후 stopPropagation() 필요 가능 |
한줄 요약
$('.menu-box li')로 모든 메뉴 항목에 클릭 이벤트를 적용하여 n차 메뉴도 동일하게 열고 닫을 수 있도록 확장함.
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 메뉴 클릭 시 해당 항목만 .active 토글됨 |
| 문제 상황 | 형제 메뉴들도 동시에 .active 상태가 될 수 있음 → UX 혼란 |
| 기대 동작 | 현재 클릭한 메뉴만 .active 유지, 나머지 형제 항목은 .active 제거 |
| 목적 | 아코디언 메뉴처럼 한 번에 하나의 메뉴만 열리게 제한 |
정답 동작 설명
클릭된 메뉴 항목(this)에만.active추가
siblings()메서드로 형제 항목의.active는 제거
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 여러 메뉴 동시에 활성화 가능 | O | X (하나만 열림) |
| 형제 메뉴의 상태 제어 | 없음 | .siblings().removeClass('active') 적용 |
| UX 직관성 | 낮음 | 높음 |
JS 코드 해석
$('.menu-box li').click(function (e) { $(this).siblings().removeClass('active');// 형제 요소 비활성화
$(this).toggleClass('active');// 자기 자신만 토글
});
siblings()는 현재 클릭된 li와 같은 부모를 가진 형제 요소들을 선택함- 클릭 시 자기만
.active,나머지는 제거됨
핵심 정리표
| 개념 | 설명 |
|---|---|
.siblings() | 같은 부모를 가진 형제 요소 선택 |
.removeClass('active') | 기존에 열려 있던 항목 닫기 |
.toggleClass('active') | 클릭된 항목만 열기 |
| UX 효과 | 여러 메뉴가 동시에 열리는 혼란 방지 |
한줄 요약
클릭한 메뉴만.active로 유지하고, 형제 메뉴는 닫아주는 아코디언 방식으로 UX를 깔끔하게 개선함.
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 형제 메뉴는 닫히지만, 형제 메뉴 안에 열려 있던 하위 메뉴는 그대로 남음 |
| 문제 상황 | 하위 메뉴들이 열린 상태로 유지됨 → 메뉴 상태가 꼬일 수 있음 |
| 기대 동작 | 형제 메뉴와 그 하위 메뉴 모두 .active 제거 |
| 목적 | 클릭한 메뉴 외의 모든 관련 항목을 닫아서 UI 정합성 유지 |
정답 동작 설명
- 클릭한
li의siblings()를 통해 형제 메뉴 선택- 거기에
.find('*')로 모든 하위 자식까지 선택해서.removeClass('active')처리
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 형제 메뉴 닫힘 | O | O |
| 형제 메뉴의 하위 항목 닫힘 | X (열린 상태 유지됨) | O (siblings().find('*').removeClass('active')) |
| UI 상태 정리 | 미흡 | 완전 정리됨 |
JS 코드 해석
$('.menu-box li').click(function (e) {
// 형제 및 그 하위 요소에서 active 제거
$(this).siblings().find('*').removeClass('active');
$(this).siblings().removeClass('active');
// 현재 클릭한 메뉴 토글
$(this).toggleClass('active'); });
.siblings()는 같은 부모의 형제를 찾고.find('*')는 그 안의 모든 후손을 찾음전부 .removeClass('active')해서 초기화
핵심 정리표
| 개념 | 설명 |
|---|---|
.siblings() | 형제 요소 선택 |
.find('*') | 하위 모든 자식 요소 선택 |
.removeClass('active') | 열린 메뉴를 닫기 |
| 메뉴 정리 목적 | 하위 메뉴까지 깔끔하게 접기 |
한줄 요약
메뉴 클릭 시 형제뿐 아니라 형제의 모든 하위 메뉴까지.active를 제거하여, 메뉴 상태를 깔끔하게 초기화함.
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 이미 열린 메뉴를 다시 클릭하면 해당 항목은 닫히지만, 하위 메뉴는 .active가 그대로 남아 있음 |
| 문제 상황 | 하위 메뉴가 시각적으로는 사라지지 않지만 내부적으로는 .active 상태 유지됨 |
| 기대 동작 | 이미 .active 상태인 항목을 다시 클릭하면 그 후손의 .active도 함께 제거됨 |
| 목적 | 재클릭 시 전체 계층 상태를 초기화하여 UI 일관성 확보 |
정답 동작 설명
- 클릭한
li가 이미.active상태일 경우:
$(this).find('*').removeClass('active')실행 → 하위 메뉴 초기화- 그 외에는 기존 방식대로 형제 초기화 및 자신 토글
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 재클릭 시 자기 자신 닫힘 | O | O |
| 재클릭 시 후손 상태 유지됨 | O (초기화 안 됨) | X (모든 후손 .active 제거) |
| 클릭 동작 정합성 | 중간 | 향상됨 (완전 초기화) |
JS 코드 해석
$('.menu-box li').click(function (e) { const $clicked = $(this);
// 이미 active 상태면 → 후손 초기화
if ($clicked.hasClass('active')) { $clicked.find('*').removeClass('active'); }
// 형제 및 후손 초기화
$clicked.siblings().removeClass('active');
$clicked.siblings().find('*').removeClass('active');
// 현재 항목 토글
$clicked.toggleClass('active'); });
hasClass('active')를 먼저 확인 → 자기 내부의 상태를 먼저 초기화- 이후 형제 및 그 하위까지 초기화한 뒤 자기 자신 토글
핵심 정리표
| 개념 | 설명 |
|---|---|
.hasClass('active') | 현재 메뉴가 열려 있는지 확인 |
.find('*').removeClass() | 하위 메뉴까지 전부 초기화 |
.siblings().find('*') | 형제의 하위 메뉴 초기화 |
| 클릭 로직 분기 처리 | 상태에 따라 다르게 작동 |
한줄 요약
이미 열린 메뉴를 다시 클릭하면 자기 자신뿐 아니라 모든 하위 메뉴도 .active 제거하여 완전한 초기화를 구현함.
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 모바일 메뉴(사이드바)는 항상 열려 있음 |
| 문제 상황 | 메뉴를 열거나 닫는 기능이 없음 → 실제 서비스 환경에서 불편 |
| 기대 동작 | 햄버거 버튼 클릭 시 메뉴 열리고, 닫기 버튼 클릭 시 메뉴 닫힘 |
| 목적 | 사용자 주도적으로 모바일 메뉴를 제어할 수 있도록 기능 추가 |
정답 동작 설명
- 햄버거 버튼 클릭 → 메뉴 전체(
.mobile-side-bar)에.active추가 → 메뉴 표시- 닫기 버튼 클릭 →
.active제거 → 메뉴 닫힘- 메뉴 전체를 하나의 컨테이너로 제어
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 메뉴 열기/닫기 기능 존재 | X | O |
| 사용자 상호작용 제어 가능 | X | O |
.active로 전체 메뉴 제어 | X | O |
JS 코드 해석
// 메뉴 열기
$('.btn-show-mobile-side-bar').click(function () { $('.mobile-side-bar').addClass('active'); });
// 메뉴 닫기
$('.btn-close-mobile-side-bar').click(function () { $('.mobile-side-bar').removeClass('active'); });
- 메뉴 열기 버튼과 닫기 버튼에 각각 이벤트를 부여
.mobile-side-bar에 .active클래스가 있을 때만 메뉴 표시
CSS 제어 예시
.mobile-side-bar { display: none; }
.mobile-side-bar.active { display: block; }
또는transform,opacity,visibility등으로 애니메이션 처리 가능
핵심 정리표
| 개념 | 설명 |
|---|---|
.addClass('active') | 메뉴 열기 |
.removeClass('active') | 메뉴 닫기 |
| 전체 메뉴 박스를 하나의 엘리먼트로 제어 | .mobile-side-bar 기준 |
한줄 요약
햄버거 버튼 클릭 시.mobile-side-bar에.active클래스를 추가/제거하여 모바일 메뉴 전체를 열고 닫는 기능을 구현함.
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 모바일 메뉴 닫기 버튼으로 메뉴는 닫히지만, 열려 있던 메뉴 항목(.active) 상태는 그대로 유지됨 |
| 문제 상황 | 다시 메뉴를 열었을 때 이전 메뉴가 열려 있음 → 혼란 유발 |
| 기대 동작 | 닫기 버튼 클릭 시, 메뉴 닫기와 함께 .active 클래스 전체 제거 |
| 목적 | 메뉴를 닫을 때 메뉴 상태까지 완전 초기화 |
정답 동작 설명
- 닫기 버튼 클릭 시:
.mobile-side-bar에서.active제거 → 메뉴 닫기.mobile-side-bar .active모두 찾아서.removeClass('active')처리 → 상태 초기화
문제 vs 정답 비교표
| 항목 | 문제 코드 | 정답 코드 |
|---|---|---|
| 메뉴 닫기 기능 | O | O |
| 열려 있던 메뉴 상태 유지 | O | X |
| 메뉴 상태 초기화 | X | O |
JS 코드 해석
// 닫기 버튼 클릭 시
$('.btn-close-mobile-side-bar').click(function () { $('.mobile-side-bar').removeClass('active');// 메뉴 닫기
$('.mobile-side-bar .active').removeClass('active');// 메뉴 상태 초기화
});
핵심 정리표
| 개념 | 설명 |
|---|---|
.removeClass('active') | 닫기 버튼 동작에 메뉴 상태 초기화 추가 |
.mobile-side-bar .active 선택 | 메뉴 내부에서 열린 모든 항목 대상 |
| UX 효과 | 메뉴를 다시 열었을 때 깔끔한 초기 상태 제공 |
한줄 요약
- 닫기 버튼 클릭 시 메뉴 닫기뿐 아니라 모든
.active클래스도 함께 제거해, 다음에 열 때 깔끔한 상태로 시작되도록 함.
문제점 설명
| 항목 | 설명 |
|---|---|
| 현재 상태 | 앞에서 구현한 기능들이 각각 따로 있음 (분리된 단계별 코드) |
| 문제 상황 | 메뉴 열기/닫기, active 제어, n차 메뉴, 초기화 등 기능이 분산되어 일관성 부족 |
| 기대 동작 | 전체 기능을 하나로 병합하고, 메뉴 영역에 스크롤(overflow-y-auto) 적용 |
| 목적 | 실제 서비스에서 사용 가능한 완성도 있는 모바일 메뉴 시스템 구축 |
정답 동작 설명
- 메뉴 열기/닫기 기능 구현
- 메뉴 클릭 시:
- 형제 및 후손의 .active 제거
- 자기 자신 .active 토글
- 이미 .active 상태면 자기 후손의 .active도 제거
- 메뉴 닫을 때 전체 .active 상태 초기화
- 메뉴 컨테이너에 overflow-y-auto 적용해 스크롤 가능
주요 변경 비교표
| 기능 | 이전 단계까지 | 12단계 통합 버전 |
|---|---|---|
| 메뉴 열기/닫기 | O | O |
| n차 메뉴 동작 | O | O |
| 메뉴 클릭 시 상태 초기화 | O | O |
| 메뉴 닫을 때 전체 초기화 | O | O |
| 스크롤 가능 | X | O (overflow-y-auto) |
JS 코드 해석 (최종 통합)
// 메뉴 열기
$('.btn-show-mobile-side-bar').click(function () { $('.mobile-side-bar').addClass('active'); });
// 메뉴 닫기
$('.btn-close-mobile-side-bar').click(function () { $('.mobile-side-bar').removeClass('active'); $('.mobile-side-bar .active').removeClass('active'); });
// 메뉴 클릭 동작
$('.menu-box li').click(function () { const $clicked = $(this);
if ($clicked.hasClass('active')) {
$clicked.find('*').removeClass('active');// 자기 후손 초기화
}
$clicked.siblings().removeClass('active');
$clicked.siblings().find('*').removeClass('active');
$clicked.toggleClass('active'); });
CSS 핵심 적용
.mobile-side-bar__content { overflow-y: auto; }
- 메뉴 콘텐츠 영역에 세로 스크롤 적용
- 많은 메뉴 항목이 있을 때 화면 넘침 방지
핵심 정리표
| 개념 | 설명 |
|---|---|
.addClass() / .removeClass() | 메뉴 열고 닫기 |
.toggleClass('active') | 클릭 시 상태 변경 |
.siblings().find('*') | 형제 + 자식 초기화 |
overflow-y: auto | 메뉴 영역 스크롤 허용 |
한줄 요약
앞 단계 모든 기능을 통합하고, 스크롤 가능한 구조(overflow-y-auto)까지 적용하여 완성도 있는 반응형 모바일 메뉴 시스템을 구축함.
전체 목표
- 모바일 환경에서 다단계 메뉴(1차/2차/3차)를 동적으로 열고 닫을 수 있도록 구현
- 메뉴 클릭 시 활성화 상태(.active)를 관리하고 UX를 고려한 계층적 제어 적용
- 메뉴가 켜질 때/꺼질 때의 동작 일관성 확보
- 오직 CSS가 아닌 jQuery로 유연하고 확장 가능한 메뉴 인터랙션 구현
단계별 요약
| 단계 | 주요 내용 | 핵심 포인트 |
|---|---|---|
| 1단계 | BEM 방식으로 마크업 격리 | .mobile-menu-box, .mobile-side-bar, .menu-box 등 구조 설계 |
| 2단계 | 메뉴 마크업 작성 | 1차/2차/3차 메뉴를 리스트로 구성하여 HTML 작성 완료 |
| 3단계 | :not(:only-child) 조건 사용 | 하위 메뉴가 있는 항목에만 화살표 표시 |
| 4단계 | 배경 반투명 중첩 | 다중 메뉴가 겹쳐도 배경 흐림 유지 (rgba 활용) |
| 5단계 | 아이템 클릭 시 active 토글 | .active 클래스 toggle로 열고 닫기 구현 |
| 6단계 | 하위 메뉴에도 이벤트 적용 | 2차, 3차 메뉴까지 동일한 동작 구현 |
| 7단계 | 형제의 active 제거 | 같은 단계 형제 메뉴가 열리지 않도록 제한 |
| 8단계 | 형제의 후손 active도 제거 | 계층 아래까지 비활성화되어야 함 (하위 항목까지) |
| 9단계 | 현재 활성 메뉴 재클릭 시 하위만 닫힘 | 부모는 유지, 후손만 active 제거 |
| 10단계 | 모바일 메뉴 열고 닫는 기능 | .mobile-menu-box.active 제어로 표시/숨김 구현 |
| 11단계 | 메뉴 닫을 때 모든 active 초기화 | find('.active')로 하위 모든 메뉴 상태 초기화 |
| 12단계 | 전체 병합 및 overflow-y-auto 적용 | 스크롤 가능한 구조 완성, 메뉴 구조 전체 통합 |
핵심 기능 흐름 요약
| 기능 | jQuery 로직 요약 |
|---|---|
| 메뉴 열기 | .click() → addClass('active') |
| 메뉴 닫기 | .click() → removeClass('active') or toggleClass() |
| 형제 비활성화 | .siblings().removeClass('active') |
| 후손 비활성화 | .find('.active').removeClass('active') |
| 메뉴 전체 초기화 | .mobile-menu-box .active 전부 제거 |
| 스크롤 가능 메뉴 | .mobile-side-bar__content에 overflow-y: auto 적용 |
핵심 개념 정리
| 개념 | 설명 |
|---|---|
| BEM 방식 | 메뉴 구성의 명확한 역할 분리를 위한 클래스 네이밍 |
| 이벤트 위임 | .click()을 사용해 단계별 메뉴 요소에 동작 부여 |
| 클래스 제어 | addClass, removeClass, toggleClass, siblings, find 등 활용 |
| UX 고려 | 메뉴 상태가 꼬이지 않도록 단계적 active 제어 |
한줄 요약
단계별로 메뉴 열기/닫기 및 계층 제어 로직을 구현하여, UX 좋은 3단계 반응형 모바일 메뉴 완성
관련영상
침착맨의 디자인 감각 테스트하기