반응형
반응형 웹에서 사용하면 좋을
제이쿼리(jQuery) GNB
들어가기에 앞서
반응형 웹사이트를 구축하기위해서 기존에 사용하던 PC GNB(Global Navigation Bar)와 모바일 햄버거 메뉴(mobile burger menu)를 각각 만들어 CSS show/hide로 기능을 구현했었습니다. 그러던 중 지난 프로젝트에서 사용했던 유용한 코드가 있어서 이웃님들께 소개해 드려봅니다.
아래 코드는 HTML5, CSS3, jQuery를 원할하게 이해하고 수정할 수 있는 능력이 필요합니다. 난이도 (중급 / ★★★☆ ☆) 제이쿼리 버전은 1.8.21.이며, 최신버전에서도 정상적으로 동작합니다.
HTML5
<!-- [S] header -->
<header class="header">
<div class="header-inner">
<h1 class="logo"><a href="/"><img src="/images/resp/logo.png" alt="logo" /></a></h1>
</div>
<!-- [S] mobile -->
<div class="mo-gnb-bg"></div>
<span class="mo-gnb-open">
<button type="button"><span class="skip">메뉴열기</span></button>
</span>
<!-- [S] gnb-box -->
<div class="gnb-box">
<div class="gnb-box-inner">
<span class="mo-gnb-close">
<button type="button"><span class="skip">메뉴닫기</span></button>
</span>
<!-- [S] gnb -->
<div class="gnb" id="gnb">
<h2 class="skip">상단 메인메뉴 영역</h2>
<ul>
<!-- [S] menu1 -->
<li class="depth1 menu1">
<a href="#" class="tit">대메뉴</a><!-- on : 서브페이지 메뉴 활성화 -->
<!-- [S] depth2 -->
<div class="top2m menuBox">
<div class="top2m-inner">
<ul class="top2m-list">
<li class="depth2 depth2-m1">
<a class="depth2-tit plus" href="#"><span class="depth2_text">depth2</span></a>
<div class="top3m">
<ul class="MkSub">
<li><a href="#">depth3</a></li>
<li><a href="#">depth3</a></li>
<li><a href="#">depth3</a></li>
</ul>
</div>
</li>
</ul>
</div>
</div>
<!--// [E] depth2 -->
</li>
</ul>
</div>
<!-- <div class="pc-gnb-bg"></div> -->
</div>
</div>
<!-- // [E] gnb-box -->
</header>
<!-- // [E] header -->
CSS3
반응형 웹 코드를 작성하기 때문에 CSS에는 미디어 쿼리를 사용하여 디바이스 분기를 해주어야 합니다.
- 디바이스 분기
- laptop ~ PC(1024이상)
- 타블렛 (769~1023)
- mobile (320 ~ 768)
/***************** breakpoint *****************/
@media only screen and (max-width: 1320px) {
}
/***************** tablet *****************/
@media only screen and (max-width: 1023px) {
#wrap {
overflow-x: hidden;
}
.header .menu-all {
display: none;
}
.header-util .util-left {
display: none;
}
.headerFixed {
top: 0px;
}
.headerFixed .header-inner {
border-bottom: 1px solid #cccccc;
}
/*header*/
.header {
height: auto;
padding-top: 0px;
}
.header .header-inner {
width: 100%;
max-width: 100%;
height: 60px;
border-bottom: 1px solid #cccccc;
} /* 0320 수정 */
.header .logo {
top: 50%;
transform: translateY(-50%);
left: 10px;
}
.header .logo a {
width: 186px;
background-position: left center;
}
/* mo-gnb */
.header .mo-gnb-open {
display: block;
position: absolute;
top: 50%;
transform: translateY(-50%);
right: 10px;
width: 32px;
height: 32px;
z-index: 110;
}
.header .mo-gnb-open button {
display: block;
width: 100%;
height: 100%;
background: red url(/static/cpa/img/icon-menu-all.png) no-repeat center;
background-size: 100% auto;
}
.header .mo-gnb-close {
display: block;
position: absolute;
top: 16px;
right: 10px;
width: 28px;
height: 28px;
z-index: 61;
}
.header .mo-gnb-close button {
display: block;
width: 100%;
height: 100%;
background: url(/static/cpa/img/mo-gnb-close.png) no-repeat center center;
background-size: 100%;
}
.header .mo-gnb-bg {
display: none;
position: fixed;
z-index: 500;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.7);
}
.header .pc-gnb-bg,
.header .pc-gnb-bg.on {
display: none;
background: none;
transition: none;
}
/* gnb-box */
.header .gnb-box {
display: none;
position: fixed;
top: 0px;
right: 0px; /* right:-336px; */ /* transition-duration: 0.3s; */
z-index: 501;
}
.header .gnb-box > .gnb-box-inner {
position: relative;
width: 300px;
min-height: auto;
background-color: #fff;
height: 100vh;
overflow-y: scroll;
}
/* header-util */
.header-util {
position: static;
top: 0px;
left: 0px;
width: 100%;
height: 104px;
border-bottom: none;
z-index: 60;
background-color: #1d68dc;
}
.header-util .header-util-inner {
width: 100%;
max-width: 100%;
}
.header-util .util-member {
flex-wrap: wrap;
align-items: flex-end;
width: 100%;
padding: 16px 20px;
}
.btn-util-member {
flex: none;
width: auto;
height: auto;
}
.btn-util-member:first-of-type::after {
display: none;
}
.btn-util-member.join {
width: 100%;
margin-bottom: auto;
}
.btn-util-member.name {
width: 100%;
margin-bottom: auto;
display: block;
color: #fff;
}
.btn-util-member.name span,
.btn-util-member.join span {
font-size: 1.8rem;
font-weight: 700;
line-height: 2.8rem;
}
/* .btn-util-member > a::before {width: 18px; height: 18px;}
.btn-util-member::after {margin: 0 8px;} */
.btn-util-member.mydoc > a::before,
.btn-util-member.mymod > a::before {
display: none;
}
/* gnb(menu) */
.gnb-box .gnb {
display: block;
width: 100%;
background: #fff;
}
/*gnb > depth1*/
.gnb-box .gnb > ul {
position: static;
top: 0px;
left: 0px;
width: 100%;
padding: 12px 20px;
}
.gnb-box .gnb > ul li.depth1 {
float: none;
border-bottom: 1px solid #eaeaea;
}
.gnb-box .gnb > ul li.depth1:last-of-type {
margin-bottom: 100px;
}
.gnb-box .gnb > ul li.depth1.menu1 {
margin-left: 0px;
}
.gnb-box .gnb > ul li.depth1 > a.tit {
padding: 12px 0;
margin: 0px;
height: auto;
font-size: 1.8rem;
line-height: 2.8rem;
color: #333;
font-weight: 500;
background: url(/static/cpa/img/icon-gnb-1dep.png) no-repeat right center;
background-size: 28px !important;
}
.gnb-box .gnb > ul li.depth1 > a.tit.on {
color: #1d68dc;
background: url(/static/cpa/img/icon-gnb-1dep-on.png) no-repeat right center;
}
.gnb-box .gnb > ul li.depth1 > a.tit.on::after {
display: none;
}
/* .gnb-box .gnb > ul li.depth1 > a.tit > span.on{ border-bottom: 5px solid #1e58af; } */
/*gnb > 좌측타이틀*/
.gnb-box .gnb .top2m {
display: none;
position: static;
background: none;
border-bottom: 0px;
}
.gnb-box .gnb .top2m .top2m-inner {
width: 100%;
max-width: 100%;
}
.gnb-box .gnb .top2m .top2m-inner .top2m-title {
float: none;
display: none;
}
/*gnb > depth2*/
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list {
float: none;
min-height: auto;
width: 100%;
border-left: none;
padding: 0 12px;
background: none;
background-color: #f8fafb;
transition: none;
box-sizing: border-box;
}
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list li.depth2 {
float: none;
position: static;
left: 0px;
top: 0px;
right: 0px;
bottom: 0px;
padding: 0px;
margin: 0px;
width: auto;
}
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list li a.depth2-tit {
position: static;
display: block;
padding: 12px 0;
font-size: 1.4rem;
font-weight: 400;
color: #000;
background-color: #f8fafb;
border-top: 1px dashed #eaeaea;
white-space: nowrap;
transition: none;
}
.gnb-box
.gnb
.top2m
.top2m-inner
ul.top2m-list
li:first-of-type
a.depth2-tit {
border-top: 0px;
}
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list li a.depth2-tit.plus {
background: url(/static/cpa/img/icon-gnb-2dep.png) no-repeat right center;
background-size: 24px !important;
background-color: #f8fafb;
}
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list li a.depth2-tit.plus.on {
background: url(/static/cpa/img/icon-gnb-2dep-on.png) no-repeat right center;
}
/* .gnb-box .gnb .top2m .top2m-inner ul.top2m-list li+li{ border-top:1px dashed #EAEAEA;} */
.gnb-box .gnb .menu3 .top2m .top2m-inner ul.top2m-list li.depth2 {
margin-right: 0;
}
/*gnb > depth3*/
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list li .top3m {
display: none;
border-top: 1px dashed #eaeaea;
}
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list li .top3m ul {
margin-top: 0px;
padding: 12px 0;
}
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list li .top3m ul li {
margin-top: 8px;
}
.gnb-box
.gnb
.top2m
.top2m-inner
ul.top2m-list
li
.top3m
ul
li:first-of-type {
margin-top: 0px;
}
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list li .top3m ul li a {
display: block;
font-weight: 400;
color: #666;
}
.gnb-box .gnb .top2m .top2m-inner ul.top2m-list li .top3m ul li a:hover {
color: #1d68dc;
font-weight: 500;
}
}
/***************** mobile *****************/
@media only screen and (max-width: 767px) {
}
jQuery
전체를 감싸는 #wrap 크기(width)를 감지하여 Wide, Tablet, Mobile 클래스를 부여합니다.
$(document).ready(function () {
/*************** 창크기감지******************/
var windowWidth = $("#wrap").width();
KindOfEquipment = 3;
if (windowWidth > 1024) {
if ($("body").find(".Wide").length) {
$("#wrap").removeClass("Tablet");
$("#wrap").removeClass("Mobile");
/* headerFixed(40, 120) //0320 삭제 */
} else {
$("#wrap").removeClass("Tablet");
$("#wrap").removeClass("Mobile");
$("#wrap").addClass("Wide");
}
}
if (windowWidth <= 1024 && windowWidth > 768) {
if ($("body").find(".Tablet").length) {
$("#wrap").removeClass("Wide");
$("#wrap").removeClass("Mobile");
} else {
$("#wrap").removeClass("Wide");
$("#wrap").removeClass("Mobile");
$("#wrap").addClass("Tablet");
/* headerFixed(0, 60) //0320 삭제 */
}
}
if (windowWidth <= 768) {
if ($("body").find(".Mobile").length) {
$("#wrap").removeClass("Wide");
$("#wrap").removeClass("Tablet");
} else {
$("#wrap").removeClass("Wide");
$("#wrap").removeClass("Tablet");
$("#wrap").addClass("Mobile");
/* headerFixed(0, 60) //0320 삭제 */
}
}
if ($("#wrap").is(".Wide")) {
KindOfEquipment = 3;
}
if ($("#wrap").is(".Tablet")) {
KindOfEquipment = 2;
}
if ($("#wrap").is(".Mobile")) {
KindOfEquipment = 1;
}
ResizeSituation = 0;
$(window).resize(function () {
$("body").removeClass("menu-on");
var windowWidth = $("#wrap").width();
if (windowWidth <= 1024 && windowWidth > 768) {
if (ResizeSituation != 1) {
if ($("body").find(".Tablet").length) {
$("#wrap").removeClass("Wide");
$("#wrap").removeClass("Mobile");
} else {
$("#wrap").removeClass("Wide");
$("#wrap").removeClass("Mobile");
$("#wrap").addClass("Tablet");
}
$(".header .gnb-box").css(
"display",
"none"
); /* 0320 - 모바일헤더 수정 */
$(".mo-gnb-bg").hide();
// $('.gnb-box .gnb > ul li.depth1 > a.tit').removeClass('on');
/* headerFixed(0, 60) //0320 삭제 */
ResizeSituation = 1;
KindOfEquipment = 2;
} else {
return false;
}
}
if (windowWidth <= 768) {
if (ResizeSituation != 2) {
if ($("body").find(".Mobile").length) {
$("#wrap").removeClass("Wide");
$("#wrap").removeClass("Tablet");
} else {
$("#wrap").removeClass("Wide");
$("#wrap").removeClass("Tablet");
$("#wrap").addClass("Mobile");
}
/* headerFixed(0, 60) //0320 삭제 */
$(".header .gnb-box").css(
"display",
"none"
); /* 0321 - 모바일헤더 추가 */
ResizeSituation = 2;
KindOfEquipment = 1;
} else {
return false;
}
}
if (windowWidth > 1024) {
if (ResizeSituation != 3) {
if ($("body").find(".Wide").length) {
$("#wrap").removeClass("Tablet");
$("#wrap").removeClass("Mobile");
} else {
$("#wrap").removeClass("Tablet");
$("#wrap").removeClass("Mobile");
$("#wrap").addClass("Wide");
}
$(".header .gnb-box").css(
"display",
"block"
); /* 0320 - 모바일헤더 수정 */
$(".top2m").css({ display: "none" });
$(".top3m").removeAttr("style");
$(".tabBox .list").show(); //서브 탭메뉴
$("body").removeClass("popup-on");
/* headerFixed(40, 120) //0320 삭제 */
ResizeSituation = 3;
KindOfEquipment = 3;
} else {
return false;
}
}
});
/************GNB-PC용******************/
var currGnb_index = null;
//gnb 열기
$(".gnb .depth1")
.children("a")
.on({
"mouseenter focusin": function () {
if (KindOfEquipment == 3) {
if ($(this).parent().index() != currGnb_index) {
//현재 대메뉴 에서 다시 마우스 오버시 깜박임 방지
$(".top2m").hide();
$(".gnb .depth1").removeClass("on");
$(this).parent().addClass("on");
var HH = $(this).siblings(".top2m").height();
//alert("기본 받은값"+HH);
$(this)
.siblings(".top2m")
.find(".top2m-title")
.css("height", HH); /*좌우 높이 같게 */
$(".pc-gnb-bg")
.addClass("on")
.css("height", HH + 2);
$(this).siblings(".top2m").stop().show();
currGnb_index = $(this).parent().index();
}
}
}
});
//gnb닫기
$(".gnb").on({
mouseleave: function () {
if (KindOfEquipment == 3) {
$(".top2m").hide();
$(".gnb .depth1").removeClass("on");
$(".pc-gnb-bg").removeClass("on").css("height", "0");
currGnb_index = null;
}
}
});
//gnb(pc) 마지막 focusout 처리
var $gnbLast3m = $(".gnb > ul > li:last-child")
.prev()
.find(".top2m-list > li:last-child > .top3m ul li:last-child"); //0203 수정
var $gnbLast2m = $(".gnb > ul > li:last-child")
.prev()
.find(".top2m-list > li:last-child"); //0203 수정
if ($gnbLast3m.length) {
$gnbLast3m.on({
focusout: function () {
if (KindOfEquipment == 3) {
$(".top2m").hide();
$(".gnb .depth1").removeClass("on");
$(".pc-gnb-bg").css("height", "0");
currGnb_index = null;
}
}
});
} else {
$gnbLast2m.on({
focusout: function () {
if (KindOfEquipment == 3) {
$(".top2m").hide();
$(".gnb .depth1").removeClass("on");
$(".pc-gnb-bg").css("height", "0");
currGnb_index = null;
}
}
});
}
//모바일 뎁스1 클릭
$(".gnb a.tit").on("click", function (event) {
var $target = $(event.target);
if (KindOfEquipment <= 2) {
if ($target.is(".on")) {
$(this).removeClass("on").next(".menuBox").slideUp();
//return false;
} else {
$(".gnb a.tit").removeClass("on").next(".menuBox").slideUp();
$(this).addClass("on").next(".menuBox").slideDown();
$(".top3m").removeClass("on").hide();
}
return false;
} else {
return true;
}
});
//모바일 뎁스2 클릭
$(".depth2 a.plus").on("click", function () {
if (KindOfEquipment <= 2) {
var Top3OnOff = $(this).is(".on");
if (Top3OnOff == true) {
$(this).siblings(".top3m").removeClass("on").slideUp();
$(this).removeClass("on");
return false;
} else if (Top3OnOff == false) {
$(".depth2 a.plus").not($(this)).removeClass("on");
$(this).addClass("on");
$(".top3m").not($(this).siblings()).removeClass("on").slideUp();
$(this).siblings(".top3m").addClass("on").slideDown();
return false;
}
}
});
/************모바일 GNB 열기/닫기******************/
$(".mo-gnb-open > button").on("click", function () {
$("body").addClass("popup-on");
// $('body').css({'overflow' : 'hidden'});
$(".mo-gnb-bg").show();
$(".header .gnb-box").css("display", "block"); /* 0320 - 모바일헤더 수정 */
// $('.gnb-box .gnb > ul li.depth1 > a.tit').removeClass('on');
if ($(".gnb").find(".tit.on").length) {
var $titOn = $(".gnb").find(".tit.on");
$titOn.parent(".depth1").find(".top2m").css({ display: "block" });
console.log($titOn);
} else {
}
return false;
});
$(".mo-gnb-close > button , .mo-gnb-bg").on("click", function () {
$("body").removeClass("popup-on");
// $('body').css({'overflow' : 'initial'});
/* $('.gnb a.tit').removeClass('on').next('.menuBox').hide();
$('.top3m').removeClass('on').hide(); */
$(".header .gnb-box").css("display", "none"); /* 0320 - 모바일헤더 수정 */
$(".mo-gnb-bg").hide();
return false;
});
/************전체메뉴보기******************/
$(".btn-menu-open > button").on("click", function () {
/* if ($('body').find('.headerFixed').length) { //0320 삭제
$(this).closest('.menu-all').find('.menu-list').css({'top' : 81});
} else {
$(this).closest('.menu-all').find('.menu-list').css({'top' : 121});
} */
$(this).closest(".menu-all").find(".menu-list").css({ top: 121 }); //0320 추가
$("body").addClass("menu-on");
$(".menu-all-layer").show();
$(".btn-menu-close > button").focus();
return false;
});
var $menuLast3m = $(".menu-list-inner > ul > li:last-child").find(
".depth2 > li:last-child > .depth3 ul li:last-child"
);
var $menuLast2m = $(
".menu-list-inner > ul > li:last-child .depth2 > li:last-child"
);
if ($menuLast3m.length) {
$gnbLast3m.on({
focusout: function () {
if (KindOfEquipment == 3) {
$(".btn-menu-close > button").focus();
}
}
});
} else {
$menuLast2m.on({
focusout: function () {
if (KindOfEquipment == 3) {
$(".btn-menu-close > button").focus();
}
}
});
}
$(".btn-menu-close > button").on("click", function () {
$(".menu-all-layer").hide();
$(".btn-menu-open > button").focus();
$("body").removeClass("menu-on");
return false;
});
});
마치며...
이번 포스팅에서는 반응형 웹(Responsive Web)에서 PC용 GNB와 모바일 햄버거 메뉴(mobile burger menu) 두 곳에서 다 사용할 수 있는 HTML5 + CSS3 + jQuery코드로 이웃님들을 찾아왔습니다. 다음 포스팅에서는 ES6문법에 대해서 설명해 드릴려고 합니다.
함께 읽으면 좋은 글
반응형
'FE 개발 > JavaScript' 카테고리의 다른 글
제이쿼리 모바일 햄버거 메뉴 jQeury mobile burger menu (0) | 2023.06.24 |
---|---|
제이쿼리 jQuery 햄버거 메뉴 만들기 (0) | 2023.06.24 |