메뉴 밑줄 슬라이딩 만들기

프로젝트를 개발 중 메뉴 밑줄 슬라이딩을
자연스럽게 구현하고 싶어 정리해 보았습니다.

 

용어 설명

메뉴 밑줄 슬라이딩을 구현하고 싶은데 어떻게 만들어야 할지 막막하다면 여기서 정리한 내용만 차근차근 읽어보시면

어떻게 구현하고 어떤 방식으로 만들 수 있는지 이해하실 수 있습니다.

 

특정 메뉴로 이동하고 싶을 때 애니메이션을 적용하고 싶다면 offset 이라는 기능을 사용하시면 됩니다.

그림에서 보시는 바와 같이 검정색 화면이 브라우저 화면이라고 가정해 봅시다.

그럴 때 브라우저에서 내가 측정하고 싶은 요소와 브라우저 간의 거리를 확인하고 싶다면 offsetTop 을 이용하시면 됩니다.

 

이 기능을 이용해서 간편하게 구현하시면 됩니다.

아래의 코드는 React 를 이용해서 구현한 코드입니다.

아직은 tsx 로 넘어가지 않았으니 tsx 를 이용한 메뉴 슬라이드 애니메이션을 보고 싶다면 아래 코드는 넘어가시면 됩니다.

구현

css

.navbar {
  display: flex;
  margin-bottom: 40px;
}

.navbar p {
  font-size: 30px;
  margin: 10px;
}

.horizontal-underline {
  position: absolute;
  height: 4px;
  background-color: pink;
  transition: all 1s;
}

react

import { useRef } from 'react';

const Navbar = () => {
  const underlineRef = useRef(null);

  const horizontalIndicator = (e) => {
    const target = e.target;
    const current = underlineRef.current;

    if (underlineRef.current && e.target) {
      current.style.left = `${target.offsetLeft}px`;
      current.style.width = `${target.offsetWidth}px`;
      current.style.top = `${target.offsetHeight + target.offsetTop}px`;
    }
  };

  return (
    <div className="navbar">
      <div className="horizontal-underline" ref={underlineRef}></div>
      <p onClick={horizontalIndicator}>home</p>
      <p onClick={horizontalIndicator}>about</p>
      <p onClick={horizontalIndicator}>login</p>
    </div>
  );
};

export default Navbar;

 

React 에서는 이렇게 직접 event 라는 것을 통해 해당 요소의 target 으로 접근해 offset 기능을 이용하시면 됩니다.

또한 React 는 요소에 직접적으로 style 에 접근할 수 없기 때문에  useRef 라는 hook 을 통해서 접근하시면 손쉽게 

메뉴 슬라이드 애니메이션을 구현하실 수 있습니다.

 

추가적으로 만약 tsx 로 작업하고 계신 중이시라면 아래 코드처럼 만들어 주시면 됩니다. 

위에 코드와 달리 useEffect 를 추가한 이유는 페이지가 처음 렌더링 돼었을 때 home 이라는 p 태그에 바로 underline

을 추가하기 위해서 입니다.

 

import { useRef, useEffect } from 'react';

const Navbar: React.FC = () => {
  const underlineRef = useRef<HTMLDivElement | null>(null);
  const homeRef = useRef<HTMLParagraphElement | null>(null);

  useEffect(() => {
    const current = underlineRef.current;
    const home = homeRef.current;

    if (current && home) {
      current.style.left = `${home.offsetLeft}px`;
      current.style.width = `${home.offsetWidth}px`;
      current.style.top = `${home.offsetHeight + home.offsetTop}px`;
    }
  }, []);

  const horizontalIndicator = (e: React.MouseEvent<HTMLParagraphElement>) => {
    const target = e.target as HTMLParagraphElement;
    const current = underlineRef.current;

    if (current && target) {
      current.style.left = `${target.offsetLeft}px`;
      current.style.width = `${target.offsetWidth}px`;
      current.style.top = `${target.offsetHeight + target.offsetTop}px`;
    }
  };

  return (
    <div className="navbar">
      <div className="horizontal-underline" ref={underlineRef}></div>
      <p ref={homeRef} onClick={horizontalIndicator}>
        home
      </p>
      <p onClick={horizontalIndicator}>about</p>
      <p onClick={horizontalIndicator}>login</p>
    </div>
  );
};

export default Navbar;

'React' 카테고리의 다른 글

React 에러 핸들링  (0) 2024.09.10
React 에서 formData 다루기  (0) 2024.08.21
useId  (0) 2024.08.19
useLayoutEffect  (0) 2024.08.13
React-throttle  (0) 2024.08.12