본문 바로가기

자바스크립트

[js] 카테고리 클릭 시 자동으로 따라오는 밑줄 애니메이션 만들기

반응형

결과

- 0.5x 로 각 메뉴를 클릭해 보세요.

- 그 후 더 작은 x 배율로 바꿔 보세요. 브라우저 크기에 맞춰 위치가 변경되는 것을 볼 수 있습니다.

See the Pen Untitled by youngwan2 (@youngwan2) on CodePen.

HTML 코드

    <nav class="menu_nav">
        <div id="menu_under_line"></div>
      <ul class="menu_ul">
        <li class="menu_li">Home</li>
        <li class="menu_li">About</li>
        <li class="menu_li">Programs</li>
        <li class="menu_li">Products</li>
        <li class="menu_li">Images</li>
      </ul>
    </nav>

 

CSS 코드

body {
    background-color: mediumaquamarine;
}

* {
    list-style: none;
}

/* nav */
.menu_nav {
    position: relative;
    width: 100vw;
    text-align: center;
}

/* 유니크 요소 */
.menu_nav .menu_ul {
    min-width: 600px;
}

/* 각 리스트 요소 */
.menu_nav .menu_ul .menu_li {
    display: inline-block;
    margin: 5em 15px 15px 15px;
    font-size: 18px;
}

/* 밑줄 */
#menu_under_line {
    visibility: hidden;
    transition: 1s;
    width: 100px;
    border-radius: 10px;
    height: 3px;
    position: absolute;
    top: 0;
    background-color: black;
}

 

JS  코드

 

(참고) offset 에 대해 살펴보기

더보기

- offset 은 기준이 되는 지점에서 부터 해당 요소가 얼마만큼 떨어져 있는가를 의미한다.

- 기준점(기준이 되는 지점)은 쉽게 말해 브라우저 내부의 최상단의 x, y축 좌표인  (0,0) 에 해당하는 지점이다. 

위 기준에 따라서 offsetLeft, offsetRight, offsetTop,offsetBottom 의 위치를 정리하면 다음으로 정리된다.

 

그리고 웹 브라우저에 나타난 div 태그와 같은 요소가 있다고 가정 할 때, 다음과 같이 offsetWidth, offsetHeight 를 나타낸다.

 

 

(() => {
  const underLine = document.getElementById("menu_under_line"); //밑줄 그리는 요소
  const menus = document.querySelectorAll(".menu_ul .menu_li");

  //   각 리스트의 요소를 순회하며 접근
  menus.forEach((liEl) => {
    liEl.addEventListener("click", () => {
      resizeFunc(liEl);
    });
  });

// 브라우저 크기가 달라져도 그 크기에 대응하도록 사이즈 재설정하는 함수
  const resizeFunc = (liEl) => {
    let left = liEl.offsetLeft;
    let top = liEl.offsetTop + liEl.offsetHeight;
    let width = liEl.offsetWidth;

    window.addEventListener("resize", () => {
      left = liEl.offsetLeft;
      top = liEl.offsetTop + liEl.offsetHeight;
      width = liEl.offsetWidth;

      underLineRenderingFunc(left, top, width); //재측정된 길이가 전달됨
    });
    underLineRenderingFunc(left, top, width); //제일 처음 측정된 길이가 전달됨
    // 위 두 개를 호출해야 브라우저 화면이 변경되어도 요소의 위치를 추적하여 변경된 위치로 밑줄이 재설정된다.
  };

  //   실제 밑줄을 그려주는 함수
  const underLineRenderingFunc = (left, top, width) => {
    underLine.style.visibility = "visible";
    underLine.style.width = `${width}px`;
    underLine.style.translate = `${left}px ${top + 2}px`;
  };
})();

 

 

 

반응형