styled-components 반응형 및 스타일 리셋 설정하기

시작하기

저번 포스트에서 styled-components 간단한 사용방법을 알아보았습니다.
이번 포스트에서는 브라우저 스타일을 리셋하는 방법과 함께 반응형 설정하는 방법을 알아 보겠습니다.

npm install styled-components @types/styled-components
패키지를 설치해줍니다.

초기 설정

브라우저 스타일 리셋을 하도록 하겠습니다.
먼저 styled-reset 패키지를 설치합니다.
npm install styled-reset

styles폴더내부에 글로벌 스타일 파일을 만들어줍니다.

src/styles/global-styles.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { createGlobalStyle } from 'styled-components';
import reset from 'styled-reset';

const GlobalStyle = createGlobalStyle`
${reset}
* {
box-sizing: border-box;
}
body{
background-color: #ffffff;
font-family: -apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
input, button {
background-color: transparent;
border: none;
outline: none;
}
h1, h2, h3, h4, h5, h6{
font-family:'Maven Pro', sans-serif;
}
ol, ul, li {
list-style: none;
}
img {
display: block;
width: 100%;
height: 100%;
}
`;

export default GlobalStyle;

styled-reset을 불러와 추가하고 그뒤에 리셋하고자하는 스타일을 커스텀해줍니다.

반응형 설정

styles 폴더 내부에 theme파일을 추가합니다.
이 파일은 웹사이트의 폰트나 색상등을 미리 지정할 수 있습니다.

src/styles/theme.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import baseStyled, { css, CSSProp, ThemedStyledInterface } from 'styled-components';

const sizes: { [key: string]: number; } = {
mobile: 320,
tablet: 768,
desktop: 1024
};

type BackQuoteArgs = string[];

interface Media {
mobile: (...args: BackQuoteArgs) => CSSProp | undefined,
tablet: (...args: BackQuoteArgs) => CSSProp | undefined,
desktop: (...args: BackQuoteArgs) => CSSProp | undefined,
}

const media: Media = {
mobile: (...args: BackQuoteArgs) => undefined,
tablet: (...args: BackQuoteArgs) => undefined,
desktop: (...args: BackQuoteArgs) => undefined
};

Object.keys(sizes).reduce((acc: Media, label: string) => {
switch (label) {
case 'desktop':
acc.desktop = (...args: BackQuoteArgs) => css`@media only screen and (min-width: ${sizes.desktop}px) {${args}}`;
break;
case 'tablet':
acc.tablet = (...args: BackQuoteArgs) => css`@media only screen and (max-width: ${sizes.desktop}px) and (min-width: ${sizes.tablet}px) {${args}}`;
break;
case 'mobile':
acc.mobile = (...args: BackQuoteArgs) => css`@media only screen and (max-width: ${sizes.tablet}px) {${args}}`;
break;
default:
break;
}
return acc;
}, media);

const colors = {
white: '#ffffff',
black: '#000000'
};

const secondaryColors = {};
const fontSizes: string[] = [];

const theme = {
colors,
fontSizes,
secondaryColors,
media
};

export type Theme = typeof theme;
export const styled = baseStyled as ThemedStyledInterface<Theme>;
export default theme;

이후 styles폴더내부에 theme-components 파일을 생성합니다.

src/styles/theme-components.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import * as styledComponents from 'styled-components';

import { Theme } from './theme';

const {
default: styled,
css,
keyframes,
ThemeProvider
} = styledComponents as styledComponents.ThemedStyledComponentsModule<Theme>;

export {
css,
keyframes,
ThemeProvider
};

export default styled;

아까 설정한 테마에 대한 타입을 덮어쓰기 했습니다.

적용하기

루트의 index.tsx 파일에 적용하여줍니다.

index.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import GlobalStyle from './styles/global-styles';
import theme from './styles/theme';
import { ThemeProvider } from './styles/themed-components';

ReactDOM.render(
<>
<GlobalStyle/>
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
</>, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

ThemeProvider는 단일 자식만 있어야 합니다
GlobalStyle 설정의 경우 컴포넌트 가장 위에 위치시켜주어야 모든 컴포넌트에 적용이 됩니다.

반응형 사용하기

src/App.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from 'react';
import styled from 'styled-components';

const Box = styled.div`
width: 200px;
height: 200px;
border: 1px solid red;
`
const App: React.FC = () => {

return (
<div className="App">
<Box/>
</div>
);
}

export default App;

테스트해볼 박스를 하나 생성합니다.

App.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import React from 'react';
import styled from 'styled-components';

const Box = styled.div`
width: 200px;
height 200px;
border: 1px solid red;
${({theme}) => theme.media.desktop`
border: 2px solid blue;
`}
${({theme}) => theme.media.tablet`
border: 2px solid yellow;
`}
${({theme}) => theme.media.mobile`
border: 2px solid purple;
`}
`
const App: React.FC = () => {

return (
<div className="App">
<Box/>
</div>
);
}

export default App;

반응형 스타일을 추가합니다.
props를 넘겨줘서 스타일을 사용하고 싶다면 어떻게 해야할까요?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const Box = styled.div`
width: 200px;
height 200px;
border: 1px solid red;
${({theme}) => theme.media.desktop`
border: 2px solid blue;
${(props) => `&::before{content:"데스크톱 ${props.text}"}`};
`}
${({theme}) => theme.media.tablet`
border: 2px solid yellow;
${(props) => `&::before{content:"태블릿 ${props.text}"}`};
`}
${({theme}) => theme.media.mobile`
border: 2px solid purple;
${(props) => `&::before{content:"모바일 ${props.text}"}`};
`}
`
<Box text='사이즈입니다'/>

디바이스별로 다른 제목을 넣고 싶을때 기존 사용법대로하면 다음과 같은 에러가 나옵니다

1
2
3
4
5
6
7
8
//...
${({theme}) => theme.media.mobile`
border: 2px solid purple;
${(props:{text:string}) => `&::before{
content:"태블릿 ${props.text}"
}`};
`}
//...

혹시나 해서 props에 타입을 넣어줘도 다른에러가 나옵니다.

에러!

이 경우 다음과 같이 해결할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
interface Text {
text: string;
}
const Box = styled.div<Text>`
width: 200px;
height 200px;
border: 1px solid red;
${({theme}) => theme.media.desktop`
border: 2px solid blue;
${(props: Text) => `&::before{
content:"데스크톱 ${props.text}"
}`};
`}
${({theme}) => theme.media.tablet`
border: 2px solid yellow;
${(props: Text) => `&::before{
content:"태블릿 ${props.text}"
}`}
`}
${({theme}) => theme.media.mobile`
border: 2px solid purple;
${(props: Text) => `&::before{
content:"모바일 ${props.text}"
}`}
`}
`

이렇게 타입을 따로 정의를 해주고 사용하는 위치에도 타입을 넣어 줍니다.
제대로 작동하는것을 확인할 수 있습니다.

반응형 테스트

Share