헤더 바는 볼 때마다 부자연스럽다고 생각해서 변경된 부분이 많다.
잠시 헤더 바의 역사를 보자면…
초기는 요랬다가↓
로고를 왼쪽에 넣으면서 오른쪽 위에는 목차, 가에는 Contact 아이콘을 붙였다.
또 그다음에는 로고 모양도 바꾸고, 헤더 바 자체도 떠 있는 것처럼 바꾸었고 목차도 한글로 바꾸었다.
하지만 화면을 줄이면 저 목차들이 로고와 겹쳐버려서 목차의 크기를 줄이거나 화면이 줄어들 때마다 메뉴바로 바뀌도록 구현해보았다.
그랬더니 메뉴바를 연 상태에서 화면 크기를 늘리면 메뉴바가 없어지는(...) 일이 발생한다. 이러면 곤란해지기 때문에 최종적으로는 목차를 없애고 Contact 아이콘들과 홈, mystory로 이동하는 링크를 메뉴바에 다 넣고, 헤더 바에는 로고와 메뉴바만 떠 있게 구현하였다.
메뉴바 아이콘을 가져와 준다. 헤드 바에 있는 메뉴바 아이콘을 누르면 메뉴바가 툭 튀어나오는 것이기 때문에 아이콘은 헤드 바 컴포넌트에 넣어준다.
메뉴바 컴포넌트를 따로 생성한 후 메뉴바를 그려준다.
// JSX export function Menubar () { return ( <Menubar> <MenubarWrapper> <Menu>메뉴1</Menu> <Menu>메뉴2</Menu> </MenubarWrapper> </Menubar> ) }; //styled-components export const Menubar = styled.div` display: block; position: fixed; `; export const MenubarWrapper = styled.div` position: fixed; top: 0; right: 0; bottom: 0; display: flex; flex-direction: column; width: 200px; padding: 24px; background-color: ${palette.bgColor}; `;
// store.js import React, { createContext, useState } from 'react'; export const UserContext = createContext(); export const HeadBarContext = (props) => { const [menubar, setMenubar] = useState(false); const value = { menubar, open: (toggleMenu) => setMenubar(toggleMenu), }; return ( <UserContext.Provider value={value}>{props.children}</UserContext.Provider> ); }; // App.js export default function App() { return ( <HeadBarContext> <BrowserRouter> <Routes> <Route path={'/'} element={<Home />} /> </Routes> </BrowserRouter> </HeadBarContext> ); }
import React, { useState } from 'react' export function HeadBar () { const value = useContext(UserContext); const { menubar, open } = value; ... return( <Menubar onClick={() => { open(true); }}> 메뉴바 </Menubar> ) }
1. 메뉴바 모션
framer-motion으로 motion을 만들었고 메뉴바가 열릴 때와 닫힐 때의 motion을 삼항 연산자로 motion을 넣어주었다.
const variants = { open: { x: [150, 0, 0] }, close: { x: 250 }, }; ... <MenubarWrapper animate={menubar ? 'open' : 'close'} variants={variants} </MenubarWrapper>
2. 스크롤 막기
메뉴바를 제외한 다른 화면을 클릭하면 메뉴바가 닫히게 만들기 위해 CSS로 메뉴바 뒤에 상하좌우로 꽉 찬 회색 컨테이너를 만든다.
export const Unscroll = styled(motion.div)` position: fixed; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; z-index: -1; background-color: rgba(0, 0, 0, 0.5); `;
그리고 메뉴바가 열리면 스크롤을 막아줘야 하는데 이때 body에 overflow: 'hidden'을 걸어주면 스크롤이 막히게 된다.
<Menubar onClick={() => { open(true); document.body.style.overflow = 'hidden' }}> 메뉴바 </Menubar>
3. 메뉴바 닫기
위에서 만든 스크롤을 막는 컨테이너를 클릭하면 메뉴바가 닫혀야 한다.
닫히려면 menubar 상태 값도 다시 false로 만들어 주고, 스크롤도 다시 가능케 해야 하므로 overflow: hidden도 null로 바꿔줌으로써 메뉴바가 열릴 때와는 상반된 함수를 써주면 된다.
여기서 주의해야 할 점은 메뉴바가 열리지 않은 상태에서는 이 컨테이너를 없애줘야 해서, 상태 값으로 컨트롤해준다.
{menubar ? ( <> <Unscroll onClick={() => { open(false); document.body.style.overflow = null; }} /> </> ) : null}
4. 페이지 이동
메뉴를 클릭해서 페이지가 이동하게 될 때, 메뉴바가 열려 있으면 이동하고 또 메뉴바를 닫아야 하는 불편함이 있으므로 메뉴를 클릭하면 메뉴바가 닫혀야 한다. 그러려면 메뉴가 클릭 될 때 상태 값을 다시 false로 돌려놓으면 된다.
<Menu to='/' onClick={() => { open(false); document.body.style.overflow = null; }} whileHover={{ color: palette.fontColor }}> 홈 </Menu>