하위메뉴 일체형

n-u·2022년 10월 20일
1

웹 접근성

목록 보기
3/3
post-thumbnail

이번 예제는 메뉴를 호버 및 초점 진입시 하위메뉴가 전부 나타나는 UI 디자인이다.
호버했을때 호버한 부분의 하위메뉴의 배경색이 변경되어 시각적으로 구분이 되도록 설정하였다.

특징

1. 배경색

jQuery에서는 마우스 호버에 대한 하위메뉴 배경변경만 설정되어 초접진입시 하위메뉴의 배경색이 변경되지 않는다.
Vanilla JS로 변경할때 초점 진입시에도 지정된 1depth메뉴의 하위메뉴의 배경색을 변경할 수 있도록 보충해 보았다.
(초점 부분 코드 작성할때 정말 애 많이 먹었따...ㅠ 그래서 책 예제에도 언급이 안되어 있었던 건가 싶기도 했다)

2. 하위메뉴에 최대 height값 자동 부여

이번 메뉴에서는 호버시 흰색 바탕이 메뉴의 회색영역의 높이값만큼 모든 하위메뉴가 동일하게 가져야 하는 경우이다.
css로 하나씩 지정하는 방법이 있을 수 있으나, 유지보수를 생각해보면 번거로운 일이 될 것 이다.
따라서 javascript를 이용해 하위메뉴의 높이 값을 뽑아 비교해 가장 큰 값의 높이값을 모든 하위메뉴의 높이값으로 부여하는 로직을 추가해 콘텐츠의 변화가 있어도 따로 작업을 하지 않도록 설정해 두고 있다.
(물론 회색배경색도 값은 높이값을 부여해 준다.)

jQuery
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);

});
Javascript
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`;
}   

HTML

구조적으로 간단하게 설명하자면 호버시 나타나는 회색 배경은 header섹션에 포함되어 있지 않고 div태그로 독립적으로 위치해 있다.

<header>
....
</header>
<div class='bg_gnb'></div> //<-하위메뉴의 회색 배경

이 이유는 UI 상 호버했을 당시 브라우저 화면너비를 충분히 덮어서 나타나야 하는 UI이다.
header를 중앙으로 배치하기 위해 css로 haeder에 너비값을 1160px로 설정하였다.
따라서, header의 자식으로 있게 되면 header의 너비가 최대의 너비인 1160px만큼만 표현이 되어 브라우저 화면 전체 너비만큼 나타나지 않기 때문에 독립적으로 위치시켜 body를 부모요소로 가지도록 설정해 두었다.

jQuery

Vanilla Javascript

함수 (showMenu / hideMenu)

showMenu

하위메뉴가 나타나는 동작하는 함수

특징

  • 하위메뉴와 회색 배경의 높이값을 구해 height값을 부여해 준다.
  • e.currentTargetlastElementChild
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값을 얻어내려고 해도 화면에 보이지 않기 때문에 값을 얻어 낼 수 없는 상태이다.
    • 그래서 각 하위메뉴의 height값을 얻기 위해서 display : block을 실행한 것

hideMenu

지금까지 보였던 것들을 다 없애버도록 동작한다.

function hideMenu(){
  depth2.forEach((div)=> div.style.display = 'none');
  menuBg.style.display = 'none';
}

이벤트

2. 마우스 이벤트

depth1Li.forEach((li)=> li.addEventListener('mouseenter', showMenu));
depth1Li.forEach((li)=> li.addEventListener('mouseleave', hideMenu));

3. 초점 이벤트

depth1Li.forEach((li)=> li.addEventListener('focusin',showMenu));
logo.addEventListener('focusin',hideMenu);
lang.addEventListener('focusin',hideMenu);

초점이 메뉴에 벗어날때 하위메뉴들이 보이지 않도록 하기 위해 메뉴의 앞, 뒤 요소에 초점이 진입할때 hideMenu함수를 실행시켜 하위메뉴가 보이지 않도록 한다.






마치며...

이번 예제는 이 글을 쓰면서 오류를 발견해 부랴부랴 오류(초점진입시 마우스 호버효과가 사라졌다)를 수정하고 전반적인 글을 수정하는 과정이 있었다.
초점이 메뉴에 진입 후 동시에 마우스 호버할 경우 css로 지정된 호버 효과(하위메뉴 색상변경) 동작이 작동하지 않은 오류가 발생했다.

오류 수정과정에서 불필요한 변수가 어떤 것이 있는지를 확인하게 되고 간결하게 원하는 동작을 실행 시킬 수 있는 코드가 된 것 같다.


나를 제일 애먹게 한건, 초점 진입시에 동작이었다.
초점시 e.target을 이용해 요소를 잡아내려니(초점 이동할때마다 다 다른 요소값이 찍혔다.) 여러가지 고려할 상황이 많아져 초점 이벤트에 어떻게 동작을 시킬 코드 작성에 애를 먹었다.
그러다 e.currentTarget을 이용해 고정된 기준(상위 li)로 하여 동작하도록 하니 초점에 관련된 동작을 작성할 수 있었다.

profile
기록하며 발전하는 삶

0개의 댓글