반응형 네비게이션 메뉴 구현하기

Project Diary/HTML + CSS +JS (Haitai WepSite)

 

네비게이션 메뉴

오늘은 반응형 네비게이션 메뉴를 만드는 프로젝트를 진행했다.

먼저 HTML로 기본 구조를 잡았다. 그런 다음 CSS로 스타일링을 해서 다양한 화면 크기에서도 잘 보이도록 했다. 마지막으로 JavaScript를 사용해 메뉴가 부드럽게 열리고 닫히도록 애니메이션 효과를 추가했다.

 

1. HTML 기본 구조 설정

헤더 섹션에 네비게이션 메뉴를 포함하는 구조다.

네비게이션 메뉴는 두 개의 뎁스로 구성된다: 뎁스1(depth1)과 뎁스2(depth2).

뎁스1은 네비게이션 메뉴의 최상위 항목으로 이 항목들은 화면에 항상 보이며, [제품소개],[달콤함 세상],[이벤트],[고객센터],[회사소개]가 이에 해당된다.

그리고 제품소개 메뉴를클릭하면 나오는 해태제과 캐릭터, 비스켓, 스낵 등이 뎁스2에 해당된다.

 

2. JavaScript로 동작 구현

2-1. 반응형 설정 함수 작성

화면 크기에 따라 PC와 모바일 버전을 구분하는 함수를 작성.

함수 정의 : 'getWindowWidth'

윈도우 너비를 확인하고, 너비에 따라 HTML 클래스와 스타일을 변경하는 getWindowWidth함수를 정의함

function getWindowWidth() {
    // 현재 윈도우의 너비를 변수 'ww'에 저장
    let ww = $(window).width();
    
    if (ww > 1089) {
        // PC 버전 설정
        $("html").addClass("pc").removeClass("mobile"); // 'pc' 클래스를 추가하고 'mobile' 클래스를 제거
        $("#header #nav").css({
            display: "flex", // 네비게이션을 flexbox로 표시
            width: "auto", // 너비를 자동으로 설정
        });
        $("#header .depth1 > li").removeClass("on").find(".depth2").hide(); // 모든 뎁스1 항목에서 'on' 클래스를 제거하고 뎁스2 메뉴를 숨김
        if ($("#header #nav").parent().is(".cover")) {
            $("#header #nav").unwrap(); // 만약 네비게이션의 부모 요소가 '.cover' 클래스가 있다면 해당 부모 요소를 제거
        }
    } else {
        // 모바일 버전 설정
        $("html").addClass("mobile").removeClass("pc"); // 'mobile' 클래스를 추가하고 'pc' 클래스를 제거
        $("#header #nav").css({
            display: "none", // 네비게이션을 숨김
            width: "100%", // 너비를 100%로 설정
        });
        $("#header .menuopen").find("i").removeClass("fa-times").addClass("fa-bars"); // 햄버거 메뉴 아이콘을 'fa-bars' 클래스로 변경
        $("#header #nav").removeClass("on"); // 네비게이션에서 'on' 클래스를 제거
        $("nav .depth1 > li").removeClass("on"); // 모든 뎁스1 항목에서 'on' 클래스를 제거
    }
}

함수 호출

페이지가 로드될 때 getWindowWidth 함수를 호출하여 초기 상태를 설정

getWindowWidth();

윈도우 리사이즈 이벤트 핸들러

윈도우가 리사이즈될 때마다 getWindowWidth 함수를 호출하여 상태를 업데이트

$(window).resize(function () {
    getWindowWidth();
});

 

클릭 이벤트 핸들러 설정

네비게이션 메뉴의 토글 동작과 아이콘 변경을 관리

$("#header .menuopen").on("click", function () {
    // 클릭된 요소(this)의 다음 요소를 슬라이드 토글 (보이기/숨기기)
    $(this).next().stop().slideToggle(200);

    // 클릭된 요소 안에 있는 <i> 요소가 'fa-bars' 클래스를 가지고 있는지 확인
    if (!$(this).find("i").hasClass("fa-bars")) {
        // 'fa-bars' 클래스가 없을 경우 (즉, 현재 'fa-times' 클래스일 경우)

        // 모든 뎁스2 메뉴를 슬라이드 업 (숨기기)
        $("#header #nav .depth2").slideUp();

        // 모든 뎁스1 항목에서 'on' 클래스를 제거
        $("#nav .depth1 > li").removeClass("on");

        // 아이콘을 'fa-bars'로 변경하고 'fa-times' 클래스를 제거
        $(this).find("i").addClass("fa-bars").removeClass("fa-times");
    } else {
        // 'fa-bars' 클래스가 있을 경우 (즉, 현재 'fa-bars' 클래스일 경우)

        // 아이콘을 'fa-times'로 변경하고 'fa-bars' 클래스를 제거
        $(this).find("i").addClass("fa-times").removeClass("fa-bars");
    }
});

 

 

이렇게 동작을 주고나면

반응형 네비게시연 메뉴 완성!

 

2-2. 네비게이션 메뉴 동작 설정

뎁스크탑과 모바일 버전의 네비게이션 메뉴 동작 설정

// 뎁스1의 네비게이션 항목에 마우스를 올리거나 뗄 때 실행되는 이벤트
$("#nav .depth1 > li").on("mouseover mouseout", function () {
  // HTML 태그에 'pc' 클래스가 있는 경우에만 동작
  if ($("html").hasClass("pc")) {
    // .subbg 요소를 슬라이드 토글 (열리거나 닫히는 애니메이션) 시킴
    $(".subbg").stop().slideToggle(200);
    // .subnavImg 요소를 슬라이드 토글 (열리거나 닫히는 애니메이션) 시킴
    $(".subnavImg").stop().slideToggle(200);
    // .depth2 요소를 슬라이드 토글 (열리거나 닫히는 애니메이션) 시킴
    $(".depth2").stop().slideToggle(200);
  }
});

// 뎁스2의 네비게이션 항목에 마우스를 올리거나 뗄 때 실행되는 이벤트
$("#nav .depth1 .depth2 > li").on("mouseover mouseout", function () {
  // HTML 태그에 'pc' 클래스가 있는 경우에만 동작
  if ($("html").hasClass("pc")) {
    // 현재 항목의 부모 요소 (즉, .depth1 > li 요소)에 'on' 클래스를 토글
    $(this).parent().parent().toggleClass("on");
    // 현재 항목의 부모 요소의 형제 요소들에서 'on' 클래스를 제거
    $(this).parent().parent().siblings().removeClass("on");
  }
});

// 뎁스1의 네비게이션 항목을 클릭할 때 실행되는 이벤트
$("#nav .depth1 > li").on("click", function () {
  // HTML 태그에 'mobile' 클래스가 있는 경우에만 동작
  if ($("html").hasClass("mobile")) {
    // 현재 클릭된 항목에 'on' 클래스를 토글
    $(this).toggleClass("on");
    // 클릭된 항목의 형제 요소들에서 'on' 클래스를 제거
    $(this).siblings().removeClass("on");
  }
});

// 뎁스2의 네비게이션 항목에 마우스를 올리거나 뗄 때 실행되는 이벤트
$("#nav .depth1 .depth2 > li").on("mouseover mouseout", function () {
  // 현재 항목에 'on' 클래스를 토글
  $(this).toggleClass("on");
  // 현재 항목의 형제 요소들에서 'on' 클래스를 제거
  $(this).siblings().removeClass("on");
});

데스크탑 모드:

- 뎁스1의 메뉴 항목에 마우스를 올리면 서브 메뉴 배경, 서브 메뉴 이미지, 뎁스2의 메뉴가 슬라이드 애니메이션과 함께 나타나거나 사라진다.

- 뎁스2의 메뉴 항목에 마우스를 올리면 해당 항목의 부모(.depth1 > li)에 on 클래스가 토글되고, 형제 항목의 on 클래스가 제거된다.

모바일 모드:

- 뎁스1의 메뉴 항목을 클릭하면 해당 항목에 on 클래스가 토글되고, 형제 항목의 on 클래스가 제거된다.

  •  

2-3. 하위 메뉴 이미지 토글 설정

하위 메뉴의 이미지 토글 기능을 설정

// 첫 번째 수준의 네비게이션 항목에 마우스를 올리거나 뗄 때 실행되는 이벤트
$("#nav .depth1 > li").hover(
  function () {
    // 마우스를 올린 항목의 인덱스를 가져옴
    let index = $(this).index();
    // 해당 인덱스에 맞는 클래스 (sn0, sn1, sn2 등)를 .subnavImg 요소에 추가
    $(".subnavImg").addClass("sn" + index);
    // 인덱스를 data 속성에 저장하여 나중에 사용할 수 있도록 함
    $(this).data("hoveredIndex", index);
  },
  function () {
    // 마우스를 뗀 항목의 인덱스를 data 속성에서 가져옴
    let index = $(this).data("hoveredIndex");
    // 해당 인덱스에 맞는 클래스 (sn0, sn1, sn2 등)를 .subnavImg 요소에서 제거
    $(".subnavImg").removeClass("sn" + index);
  }
);