본문 바로가기
웹 프로그래밍/🌜꿈 일기장

[React] 꿈 일기 기록 사이트 제작 일지-14. 플로팅 버튼 만들기

by 청량리 물냉면 2023. 9. 28.
반응형

꿈 일기 기록 사이트의 구상했던 메인 기능 대부분을 구현했다.

이제 소소한 추가 기능을 개발해 볼 예정이라 먼저 메뉴 버튼부터 만들기로 했다.

지금 스타일링을 최대한 보존하기 위해 플로팅 버튼으로 메뉴를 구현하려고 한다.

 

구현

먼저 플로팅 버튼 관련 코드를 작성할 FloatingMenu 컴포넌트를 생성했다.

플로팅 버튼은 모든 페이지에서 전역적으로 노출되어야 하기 때문에 App.js에 컴포넌트를 추가했다.

 

FloatingMenu.js

const FloatingMenu = () => {
  return (
    <div className="floating-menu">
      <button className="menu-btn">메뉴</button>
    </div>
  );
};

App.js

function App() {
  return (
    <div className="App">
      <DiaryProvider>
        <BrowserRouter>
          <Routes>
            ...
          </Routes>
          <FloatingMenu />
        </BrowserRouter>
      </DiaryProvider>
    </div>
  );
}
나중에 FloatingMenu에 useNavigation을 이용해 페이지 이동할 수 있는 코드를 작성할 생각이라 컴포넌트를 BrowserRouter 내부에 넣어주었다.
BrowserRouter 외부에 컴포넌트가 존재하면 usenavigate() may be used only in the context of a <router> component. 에러가 발생한다.

 

스타일링은 아래와 같이 진행했다.

 

FloatingMenu.css

.floating-menu {
  position: fixed;
  bottom: 30px;
}

.menu-btn {
  border: none;
  width: 55px;
  height: 55px;
  border-radius: 50%;
  background-color: #b18c79;

  /*버튼 안 텍스트 중앙정렬*/
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;

  white-space: nowrap;

  cursor: pointer;
  font-family: "Gothic A1", sans-serif;
  font-size: 14px;
}

플로팅 메뉴 구현에 있어서 핵심이 position: fixed이다.

플로팅 메뉴는 스크롤이 내려가도 항상 그 자리에 있어야 하기 때문에 fixed 속성을 이용했다. (fixed 대신 sticky 속성을 이용해도 동일하게 동작했다.)

 

붙어있는 메뉴 버튼은 만들었으니 버튼을 누르면 서브 메뉴가 뜨도록 코드를 구현한다.

import { useState } from "react";
import "./FloatingMenu.css";

const FloatingMenu = () => {
  const [openSubMenu, setOpenSubMenu] = useState(false);

  const shownSubMenuHandler = () => {
    setOpenSubMenu((prev) => !prev);
  };

  return (
    <div className="floating-menu">
      <div className="sub-menu">
        {openSubMenu && (
          <ul>
            <li>로그인</li>
            <li>서브메뉴</li>
            <li>서브메뉴3</li>
          </ul>
        )}
      </div>
      <button className="menu-btn" onClick={shownSubMenuHandler}>
        메뉴
      </button>
    </div>
  );
};

export default FloatingMenu;

별다른 스타일 없이 이렇게만 작성해도 리스트를 버튼 위에 띄울 수 있다. 

시행착오
처음에 div외부에서 openSubMenu &&를 작성했더니 버튼을 누를 때마다 불필요한 공간들이 생성되었다 삭제되었다.
div 위에 div 올리는 법 등등 여러 가지 찾아보다가 div는 그대로 유지하고 내부 요소들만 보이고 사라지도록 하니 원하는 플로팅 메뉴가 구현되었다.

이제 플로팅 메뉴를 보기 좋게 꾸며주고 원하는 페이지로 이동할 수 있도록 해주면 플로팅 메뉴 구현이 완료된다.

 

CSS 스타일링

.floating-menu {
  position: fixed;
  bottom: 30px;
}

.menu-btn,
.sub-btn {
  border: none;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background-color: #563a3d;

  /*버튼 안 텍스트 중앙정렬*/
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;

  white-space: nowrap;

  cursor: pointer;
  font-family: "Gothic A1", sans-serif;
  font-size: 20px;

  box-shadow: 5px 5px 5px #aaaaaa;
}

.menu-btn:hover {
}

.options {
  list-style: none;
  padding: 0px;
  margin-bottom: 10px;
}

.options li {
  margin-top: 10px;
}

.sub-btn {
  font-size: 13px;
  background: #b18c79;
}

스타일링하는 데 시간이 정말 오래 걸렸다. 

왜인지 서브메뉴를 감싸고 있는 ul에 padding, margin이 설정되어 있어서 내가 원하는 대로 스타일링이 되지 않았다. 개발자 도구로 요소들과 스타일링을 하나하나 확인해 가며 코드를 작성했다. 

그 결과 아래와 같은 플로팅 메뉴 버튼이 구현되었다.

 

여기서 중단해도 되지만 뭔가 심심해서 서브 메뉴 등장 시에 애니메이션을 주기로 했다.

@keyframes smoothAppear {
  from {
    opacity: 0;
    transform: translateY(-5%);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.options {
  ...
  animation: smoothAppear 1s;
}

애니메이션은 아래 블로그를 참고했다.

 

[CSS/React] mount/unmount 시 애니메이션 주기

첫 번째 프로젝트로 이솝 홈페이지를 클론코딩 중인데, 맡은 컴포넌트 중에서 젤 애먹었던 modal menu.... 열고 닫는 건 조건부 렌더링으로 하면 되는 거 알겠는데! 나타날 때랑 사라질 때(특!히! 사

velog.io

 

마지막으로 Auth 컴포넌트를 생성한 뒤 '로그인' 서브메뉴에 useNavigate로 연결해 주었다. 

반응형