🎉 berenickt 블로그에 온 걸 환영합니다. 🎉
Front
Styled Components
Index

1. Styling 라이브러리 종류

컴포넌트가 많은 경우 일반 CSS로 스타일링을 하다보면 불편함이 생기는데

  1. class 만들어놓은걸 까먹고 중복해서 또 만들거나
  2. 갑자기 다른 이상한 컴포넌트에 원하지않는 스타일이 적용되거나
  3. CSS 파일이 너무 길어져서 수정이 어렵거나

위 경우를 해결하기 위해 라이브러리들을 사용합니다.

💡 CSS의 문제점

  • Global Namespace : 글로벌 변수를 지양해야하는 JS와 대치
  • Dependencies : css 간의 의존 관리
  • Dead Code Elimination : 안쓰는 css 인지 어려움
  • Minification : 클래스 이름 최소화
  • Sharing Constants : JS의 코드와 값을 공유하고 싶음
  • Non-deterministic Resolution : css 파일 로드 타이밍 이슈
  • Isolation : 격리

css로 꾸밀 떄 사용하는 라이브러리는 크게 CSS-in-CSS 방식CSS-in-JS 방식으로 구분합니다.


2. Styled Components

  • JS 파일 안에서 CSS를 작성할 수 있는 대표적인 CSS-in-JS 라이브러리
  • Styled이 적용된 Component라고 해서 Styled Components라고 부름
  • https://styled-components.com/docs/basics#getting-started
  • 장점
    • Automatic critical CSS : 자동 style injects & 코드 스플릿
    • No class name bugs : unique / overlap x / misspellin
    • Easier deletion of CSS : tied to a specific component
    • Simple dynamic styling : props / global them
    • Painless maintenance : styling affecting your compon
    • Automatic vendor prefixing : current standard o

2.1 예제 : 공식문서 따라해보기

1
$ npx create-react-app styleing
2
$ cd styleing
3
$ npm install styled-components # Styled Components 설치
4
$ npm start

2.2 예제1 : 기본 사용법

2.2.1 App.js

1
import './App.css'
2
import StyledComponentsExample from './components/StyledComponentsExample/StyledComponentsExample'
3
4
export default function App() {
5
return (
6
<div className="App">
7
<StyledComponentsExample />
8
</div>
9
)
10
}

2.2.2 StyledComponentsExample

1
// src/components/StyledComponentsExample/StyledComponentsExample.jsx
2
import React from 'react'
3
import styled from 'styled-components'
4
5
export default function StyledComponentsExample() {
6
const Title = styled.h1`
7
font-size: 1.5em;
8
text-align: center;
9
color: palevioletred;
10
`
11
12
// Create a Wrapper component that'll render a <section> tag with some styles
13
const Wrapper = styled.section`
14
padding: 4em;
15
background: papayawhip;
16
`
17
18
const Button = styled.button`
19
/* Adapt the colors based on primary prop */
20
background: ${props => (props.primary ? 'palevioletred' : 'white')};
21
color: ${props => (props.primary ? 'white' : 'palevioletred')};
22
23
font-size: 1em;
24
margin: 1em;
25
padding: 0.25em 1em;
26
border: 2px solid palevioletred;
27
border-radius: 3px;
28
`
29
30
const TomatoButton = styled(Button)`
31
color: tomato;
32
border-color: tomato;
33
`
34
35
const ReversedButton = props => <Button {...props} children={props.children.split('').reverse()} />
36
37
// Use Title and Wrapper like any other React component – except they're styled!
38
return (
39
<>
40
<Wrapper>
41
<Title>Hello World!</Title>
42
</Wrapper>
43
<Button onClick={() => alert('normal')}>Normal</Button>
44
<Button onClick={() => alert('normal')} primary>
45
Primary
46
</Button>
47
<TomatoButton>Tomato 확장 버튼</TomatoButton>
48
49
<Button as="a" href="#">
50
Link with Button styles
51
</Button>
52
<TomatoButton as="a" href="#">
53
Link with Tomato Button styles
54
</TomatoButton>
55
56
<Button as={ReversedButton}>Custom Button with Normal Button styles</Button>
57
</>
58
)
59
}

2.3 예제2 : 상속(&)

1
import React from 'react'
2
import styled from 'styled-components'
3
4
const Thing = styled.div.attrs((/* props */) => ({ tabIndex: 0 }))`
5
color: blue;
6
7
// "&(ampersand)"는 현재 선택된 요소를 의미, 해당 컴포넌트 아래에 있는 자식들을 참조할 수 있음
8
&:hover {
9
color: red; // <Thing> when hovered
10
}
11
12
// 일반 형제 결합자 : 첫번쟤 요소를 뒤따르면서 같은 부모와 공유하는 2번쟤 형제 요소 선택
13
// Thing의 바로 옆은 아니지만 형제요소일 때
14
& ~ & {
15
background: tomato; // <Thing> as a sibling of <Thing>, but maybe not directly next to it
16
}
17
18
// 인접 형제 결합자 : 첫번쟤 요소를 뒤따르면서 바로 뒤에 있는 2번쟤 형제 요소 선택
19
// Thing이 바로 옆에 붙어있을 때
20
& + & {
21
background: lime; // <Thing> next to <Thing>
22
}
23
24
// Thing이 something이라는 클래스를 갖고있을 때
25
&.something {
26
background: orange; // <Thing> tagged with an additional CSS class ".something"
27
}
28
29
// // something-else라는 클래스를 가진 친구안에 있을 때
30
.something-else & {
31
border: 1px solid; // <Thing> inside another element labeled ".something-else"
32
}
33
`
34
35
export default function StyledComponentsExample() {
36
// Use Title and Wrapper like any other React component – except they're styled!
37
return (
38
<>
39
<Thing>Hello world!</Thing>
40
<Thing>How ya doing?</Thing>
41
<Thing className="something">The sun is shining...</Thing>
42
<div>Pretty nice day today.</div>
43
<Thing>Don't you think?</Thing>
44
<div className="something-else">
45
<Thing>Splendid.</Thing>
46
</div>
47
</>
48
)
49
}

2.4 예제3 : Overriding .attrs

1
import React from 'react'
2
import styled from 'styled-components'
3
4
const Input = styled.input.attrs(props => ({
5
type: 'text',
6
size: props.size || '1em',
7
}))`
8
border: 2px solid palevioletred;
9
margin: ${props => props.size};
10
padding: ${props => props.size};
11
`
12
13
// Input's attrs will be applied first, and then this attrs obj
14
const PasswordInput = styled(Input).attrs({
15
type: 'password',
16
})`
17
// similarly, border will override Input's border
18
border: 2px solid aqua;
19
`
20
21
export default function StyledComponentsExample() {
22
// Use Title and Wrapper like any other React component – except they're styled!
23
return (
24
<>
25
<Input placeholder="A bigger text input" size="2em" />
26
27
{/* Notice we can still use the size attr from Input */}
28
<PasswordInput placeholder="A bigger password input" size="2em" />
29
</>
30
)
31
}

2.5 예제4 : Animations

1
import React from 'react'
2
import styled, { keyframes } from 'styled-components'
3
4
const rotate = keyframes`
5
from {
6
transform: rotate(0deg);
7
}
8
9
to {
10
transform: rotate(360deg);
11
}
12
`
13
14
const Rotate = styled.div`
15
display: inline-block;
16
animation: ${rotate} 2s linear infinite;
17
padding: 2rem 1rem;
18
font-size: 1.2rem;
19
`
20
21
export default function StyledComponentsExample() {
22
// Use Title and Wrapper like any other React component – except they're styled!
23
return (
24
<>
25
<Rotate>&lt; 💅🏾 &gt;</Rotate>
26
</>
27
)
28
}

2.6 예제5 : Theme

1
import React, { useState } from 'react'
2
import styled, { ThemeProvider } from 'styled-components'
3
4
// Define our button, but with the use of props.theme this time
5
const Button = styled.button`
6
font-size: 1em;
7
margin: 1em;
8
padding: 0.25em 1em;
9
border-radius: 3px;
10
11
/* Color the border and text with theme.main */
12
color: ${props => props.theme.color};
13
border: 2px solid ${props => props.theme.borderColor};
14
`
15
16
// Define what props.theme will look like
17
const defaultTheme = {
18
color: 'green',
19
borderColor: 'pink',
20
}
21
22
const redTheme = {
23
color: 'red',
24
borderColor: 'red',
25
}
26
27
export default function StyledComponentsExample() {
28
const [theme, setTheme] = useState(defaultTheme)
29
// Use Title and Wrapper like any other React component – except they're styled!
30
return (
31
<div>
32
<button onClick={() => setTheme(redTheme)}>red</button>
33
<button onClick={() => setTheme(defaultTheme)}>green</button>
34
<ThemeProvider theme={theme}>
35
<Button>Normal</Button>
36
<Button>Themed</Button>
37
</ThemeProvider>
38
</div>
39
)
40
}

2.7 예제 6 : Helpers

1
import React, { useState } from 'react'
2
import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'
3
4
// Define our button, but with the use of props.theme this time
5
const Button = styled.button`
6
font-size: 1em;
7
margin: 1em;
8
padding: 0.25em 1em;
9
border-radius: 3px;
10
11
/* Color the border and text with theme.main */
12
color: ${props => props.theme.color};
13
border: 2px solid ${props => props.theme.borderColor};
14
`
15
16
// Define what props.theme will look like
17
const defaultTheme = {
18
color: 'green',
19
borderColor: 'pink',
20
}
21
22
const redTheme = {
23
color: 'red',
24
borderColor: 'red',
25
}
26
27
const GlobalStyle = createGlobalStyle`
28
button {
29
background-color : pink;
30
}
31
`
32
33
export default function StyledComponentsExample() {
34
const [theme, setTheme] = useState(defaultTheme)
35
// Use Title and Wrapper like any other React component – except they're styled!
36
return (
37
<>
38
<div>
39
<GlobalStyle />
40
<button onClick={() => setTheme(redTheme)}>red</button>
41
<button onClick={() => setTheme(defaultTheme)}>green</button>
42
<ThemeProvider theme={theme}>
43
<Button>Normal</Button>
44
<Button>Themed</Button>
45
</ThemeProvider>
46
</div>
47
<div>
48
<button>Other</button>
49
</div>
50
</>
51
)
52
}