개요
MUI의 AppBar 컴포넌트를 불러와서 navbar를 만들어줬더니,
아래 사진처럼 컨텐츠에 의해 Navbar의 그림자가 가려지는 문제가 발생했다.
이건 MUI만의 문제가 아니라, 모든 그림자를 가진 박스를 다른 요소와 바로 이어붙일 때 발생하는 문제일 것이다.
결론부터 말하자면 가상클래스 중 after를 이용해서 해결할 수 있었다.
(네비게이션을 구현하는 전 과정을 차례대로 서술하고 있으니 해결 방법만 알고 싶은 사람은 3번만 보세요!)
목차
- react-router-dom의 Outlet으로 전체에 일관되게 Nav를 추가하는 방법
- material ui의 AppBar를 커스텀하는 방법
- 가상클래스로 그림자같은 효과를 내서 문제 해결하기
1. react-router-dom의 Outlet으로 전체에 일관되게 Nav를 추가하는 방법
Outlet에는 배출구, 구멍이라는 뜻도 있는데, 그에 걸맞게 react-router-dom의 Outlet 컴포넌트를 넣은 자리에는
하위 Router의 페이지가 들어갈 수 있다.
Layout이라는 wrapper 컴포넌트를 생성하고 <Nav>와 <Outlet>을 배치해준다.
<Layout > router로 네비게이션 바가 필요한 페이지들을 감싸면 상단에는 Nav가 표시되고, 하단에는 Outlet 대신 MainPage처럼 페이지가 표시된다. 이렇게 Outlet으로 모든 페이지에 일관된 레이아웃을 적용할 수 있다.
import { Routes, Route, Outlet } from 'react-router-dom';
// ...
import Nav from './components/blocks/Nav';
const Layout = () => {
return (
<>
<Nav />
<Outlet />
</>
);
};
function App() {
return (
<Routes>
<Route element={<Layout />}>
<Route index element={<MainPage />} />
<Route path="/list" element={<ListPage />} />
</Route>
<Route path="/login" element={<LoginPage />} />
<Route path="/register" element={<RegisterPage />} />
</Routes>
);
}
Layout으로 감싸지 않은 login과 register 페이지는 Navbar가 표시되지 않는다. 특정 레이아웃이 필요한 곳만 감싸서 선택적으로 적용할 수 있다.
2. material ui의 AppBar를 커스텀하는 방법
AppBar의 default 색은 primary color를 사용하기 때문에 primary color와 다른 색깔을 지정하고 싶다면 곤란하다. (그리고 못생겼다)
이렇게 배경색을 흰색으로 바꾸고 폰트 color를 검정색으로 바꾸고 싶으면 ThemeProvider와 css를 이용해 AppBar의 css를 살짝 덮어씌우면 된다.
ThemeProvider로 App을 감싸고 globalTheme을 내려준다.
import { ThemeProvider } from '@mui/material';
import { globalTheme } from './styles/globalTheme';
// ...
root.render(
<BrowserRouter>
<ThemeProvider theme={globalTheme}>
<App />
</ThemeProvider>
</BrowserRouter>
);
globalTheme 파일에는 다음과 같이 작성해서 AppBar의 스타일을 덮어씌울 수 있다. 배경색을 흰색으로 바꾸자. boxShadow: 'none'으로 기본 그림자도 제거해준다.
export const globalTheme = createTheme({
components: {
MuiAppBar: {
styleOverrides: {
root: {
backgroundColor: 'white',
boxShadow: 'none',
},
},
},
},
});
메뉴 버튼의 폰트 색을 검정으로 바꾸려면 그 버튼을 찾아가 sx={{color: 'black'}} 처럼 스타일을 주면 된다.
3. 가상클래스 after로 그림자같은 효과 내기
다른 사이트는 이 문제를 어떻게 해결하나 궁금해서 Jira의 Navbar를 개발자도구로 검사해보니
4px의 작은 회색 div를 가상요소로 추가해서 그림자같은 효과를 내고 있었다.
3-1) 가상클래스 after에 대해 알아보기
:after
는 이름만 보면 대상의 바로 뒷쪽 붙을 것 같지만, 실제로는 내부의 마지막 자식 요소로 넣어진다.
그리고 after로 생성한 가상의 영역에 그림자를 넣어봤자 투턱처럼 그림자가 넣어지고, 컨텐츠에 그림자가 가려지는건 여전하다. 왜냐하면 그림자는 실체를 가지지 않기 때문이다.
그러므로 침범할 수 없는 영역의 내부를 그림자처럼 채울 필요가 있다.
after의 내부를 '회색 -> 서서히 옅어지도록 그라데이션 -> 흰색' 으로 그라디언트를 주면 4px 영역의 침범할 수 없는 그림자 역할을 할 수 있다.
3-2) after로 가상요소 생성하고 그라디언트로 배경 채우기
AppBar에 스타일링을 줘서 가상요소를 생성한다. emotion을 사용하고 있지 않다면 일반 style 객체 등으로 스타일링해도 된다.
높이는 4px, 배경색은 회색 그라디언트로 채워준다.
function Nav() {
return (
<AppBar position="static" css={navbarStyle}>
//...
</AppBar>
)
}
const navbarStyle = css`
&:after {
content: '';
display: block;
height: 4px;
background: linear-gradient(
rgba(9, 30, 66, 0.13) 0px,
rgba(9, 30, 66, 0.13) 1px,
rgba(9, 30, 66, 0.08) 1px,
rgba(9, 30, 66, 0) 4px
);
}
`;
그라디언트의 색상 rgba(9, 30, 66, 0.13). rgba(9, 30, 66, 0.08), rgba(9, 30, 66, 0)는 다음과 같다. 그러니까 4px 영역의 내부를 그라디언트로 만든 그림자로 채운 셈이다.
이렇게 만든 그림자는 실체가 있고 마지막 부분은 일정부분 흰색으로 채웠기 때문에, 컨텐츠가 바로 따라 붙어도 의도한 대로 그림자가 보이고 약간의 빈 공간이 있는 느낌이 든다.
'프로젝트 과정 기록' 카테고리의 다른 글
[JS] Chartjs 막대그래프 그리기 (별점 분포 차트) (0) | 2023.08.03 |
---|---|
[React] 회원가입 유효성 검사 구현하며 겪은 시행착오와 react-hook-form 사용 (0) | 2023.07.31 |
[React] 카카오 지도 API - 키워드로 장소 검색하고 목록으로 보여주기 구현 +) Typescript (0) | 2023.07.17 |
[MUI] material-ui <Link> 컴포넌트에 React-router-dom의 Link 적용하는 법 (0) | 2023.07.12 |
[MUI] material ui, emotion으로 global style 설정하기 (0) | 2023.07.12 |