이번 예제는 메뉴를 호버 및 초점 진입시 하위메뉴가 전부 나타나는 UI 디자인이다.
호버했을때 호버한 부분의 하위메뉴의 배경색이 변경되어 시각적으로 구분이 되도록 설정하였다.
jQuery에서는 마우스 호버에 대한 하위메뉴 배경변경만 설정되어 초접진입시 하위메뉴의 배경색이 변경되지 않는다.
Vanilla JS로 변경할때 초점 진입시에도 지정된 1depth메뉴의 하위메뉴의 배경색을 변경할 수 있도록 보충해 보았다.
(초점 부분 코드 작성할때 정말 애 많이 먹었따...ㅠ 그래서 책 예제에도 언급이 안되어 있었던 건가 싶기도 했다)
이번 메뉴에서는 호버시 흰색 바탕이 메뉴의 회색영역의 높이값만큼 모든 하위메뉴가 동일하게 가져야 하는 경우이다.
css로 하나씩 지정하는 방법이 있을 수 있으나, 유지보수를 생각해보면 번거로운 일이 될 것 이다.
따라서 javascript를 이용해 하위메뉴의 높이 값을 뽑아 비교해 가장 큰 값의 높이값을 모든 하위메뉴의 높이값으로 부여하는 로직을 추가해 콘텐츠의 변화가 있어도 따로 작업을 하지 않도록 설정해 두고 있다.
(물론 회색배경색도 값은 높이값을 부여해 준다.)
li.on('mouseover focusin', function(){
hig = 0;
gnbdiv.each(function(){
temp = parseInt($(this).outerHeight());
if(hig <= temp){
hig = temp;
}
});
gnbdiv.show().css('height',hig);
bg.show().css('height',hig);
});
function showMenu(e){
const eachBg = e.currentTarget.lastElementChild;
let hig = 0;
depth2.forEach((div)=> {
div.style.display = 'block';
if(div.getAttribute('style')){
let divHig = div.clientHeight;
if(hig <= divHig) hig = divHig;
}
});
depth2.forEach((div)=> {
div.style.background = 'none';
div.style.height = `${hig}px`;
});
eachBg.style.background = '#fff';
menuBg.style.display = 'block';
menuBg.style.height = `${hig}px`;
}
구조적으로 간단하게 설명하자면 호버시 나타나는 회색 배경은 header섹션에 포함되어 있지 않고 div태그로 독립적으로 위치해 있다.
<header>
....
</header>
<div class='bg_gnb'></div> //<-하위메뉴의 회색 배경
이 이유는 UI 상 호버했을 당시 브라우저 화면너비를 충분히 덮어서 나타나야 하는 UI이다.
header를 중앙으로 배치하기 위해 css로 haeder에 너비값을 1160px로 설정하였다.
따라서, header의 자식으로 있게 되면 header의 너비가 최대의 너비인 1160px만큼만 표현이 되어 브라우저 화면 전체 너비만큼 나타나지 않기 때문에 독립적으로 위치시켜 body를 부모요소로 가지도록 설정해 두었다.
하위메뉴가 나타나는 동작하는 함수
특징
- 하위메뉴와 회색 배경의 높이값을 구해 height값을 부여해 준다.
e.currentTarget
과lastElementChild
function showMenu(){
const eachBg = e.currentTarget.lastElementChild;
let hig = 0; //가장 큰 높이값을 담을 변수(비교하면서 변경되기때문에 let으로 선언)
depth2.forEach((div)=> { //forEach를 이용해 Nodelist에 접근 각 하위메뉴에 css를 적용하도록 한다.
div.style.display = 'block'; //일단 화면에 보여야 높이값을 얻을 수 있다.
// 하위메뉴 높이값 구하는 조건문
if(div.getAttribute('style')){ //하위메뉴가 style을 가지고 있다면 실행
let divHig = div.clientHeight; //각 하위메뉴의 높이값을 구해 변수에 할당
if(hig <= divHig) hig = divHig;//위에 선언한 hig와 비교하여 하위메뉴 중 높이 값이 큰 값이 결국에는 hig변수에 할당된다.
}
});
//각 하위메뉴의 높이값 지정
depth2.forEach((div)=> {
div.style.background = 'none'; //기본적인 값으로 안보이도록 설정
div.style.height = `${hig}px`;
});
//현재 이벤트가 선택된 요소의 자식(하위메뉴)의 배경색 지정
eachBg.style.background = '#fff';
//회색 배경에 높이값 및 block 지정
menuBg.style.display = 'block';
menuBg.style.height = `${hig}px`;
}
div.style.display = 'block';
먼저 실행시킨 이유display : none
인 경우에 아무리 height값을 얻어내려고 해도 화면에 보이지 않기 때문에 값을 얻어 낼 수 없는 상태이다. display : block
을 실행한 것지금까지 보였던 것들을 다 없애버도록 동작한다.
function hideMenu(){
depth2.forEach((div)=> div.style.display = 'none');
menuBg.style.display = 'none';
}
depth1Li.forEach((li)=> li.addEventListener('mouseenter', showMenu));
depth1Li.forEach((li)=> li.addEventListener('mouseleave', hideMenu));
depth1Li.forEach((li)=> li.addEventListener('focusin',showMenu));
logo.addEventListener('focusin',hideMenu);
lang.addEventListener('focusin',hideMenu);
초점이 메뉴에 벗어날때 하위메뉴들이 보이지 않도록 하기 위해 메뉴의 앞, 뒤 요소에 초점이 진입할때 hideMenu함수를 실행시켜 하위메뉴가 보이지 않도록 한다.
이번 예제는 이 글을 쓰면서 오류를 발견해 부랴부랴 오류(초점진입시 마우스 호버효과가 사라졌다)를 수정하고 전반적인 글을 수정하는 과정이 있었다.
초점이 메뉴에 진입 후 동시에 마우스 호버할 경우 css로 지정된 호버 효과(하위메뉴 색상변경) 동작이 작동하지 않은 오류가 발생했다.
오류 수정과정에서 불필요한 변수가 어떤 것이 있는지를 확인하게 되고 간결하게 원하는 동작을 실행 시킬 수 있는 코드가 된 것 같다.
나를 제일 애먹게 한건, 초점 진입시에 동작이었다.
초점시 e.target
을 이용해 요소를 잡아내려니(초점 이동할때마다 다 다른 요소값이 찍혔다.) 여러가지 고려할 상황이 많아져 초점 이벤트에 어떻게 동작을 시킬 코드 작성에 애를 먹었다.
그러다 e.currentTarget
을 이용해 고정된 기준(상위 li)로 하여 동작하도록 하니 초점에 관련된 동작을 작성할 수 있었다.