Styled-tools로 좀더 편리하게 Styled-components 사용하기
Styled-tools
는 CSS in JS 라이브러리(Styled-components
, emotion
, JSS
, etc...)로 컴포넌트 스타일링을 할 때 같이 사용할 수 있는 추상화된 유용한 함수들입니다.
Styled-tools
를 사용하신다면 좀 더 가독성이 높고 편리하게 스타일링을 하실 수 있으실 겁니다.
이 글에선 많은 CSS in JS 라이브러리들 중 가장 대중적인 Styled-components
와 함께 사용해보도록 하겠습니다.
⚠️ 이 글은 Styled-components의 기본적인 문법에 대해 알고 있다고 가정하고 작성됐습니다.
설치
먼저 npm이나 yarn을 사용해서 styled-tools
와 CSS in JS 라이브러리를 설치해줍니다.
npm i styled-tools styled-components
# 또는 yarn add styled-tools styled-components
prop
prop(path: string, defaultValue?: any): PropsFn
첫 번째 인자로 path를 받고 두 번째 인자로 기본값을 받습니다.
해당 함수는 props[path]
가 있으면 해당 값을 반환하고 없는경우 두 번째 인자로 입력받은 기본값을 반환합니다.
import styled from 'styled-components'
import { prop } from 'styled-tools'
const Button = styled.button`
color: ${prop('color', 'red')};
`
// 해당 버튼과 동일
const Button2 = styled.button`
color: ${({ color }) => color || 'red'};
`
theme
theme(path: string, defaultValue?: any): PropsFn
해당 함수는 prop
와 동일하게 첫 번째 인자로 path
를 받고 두 번째 인자로 기본값을 받습니다.
prop와의 차이점은 해당 함수는 props[path]
를 조회하는 게 아니라 props.theme[path]
를 조회합니다.
import styled from 'styled-components'
import { theme } from 'styled-tools'
const Button = styled.button`
color: ${theme('button.color', 'red')};
`
// 해당 버튼과 동일
const Button2 = styled.button`
color: ${({ theme }) => theme.button.color || 'red'};
`
palette
palette(keyOrTone?: string | number, toneOrDefaultValue?: any, defaultValue?: any): PropsFn
해당 함수는 첫 번째 인자로 key
나 tone
을 받고 두 번째 인자로 tone
또는 기본값을 받습니다 마지막 인자로 기본값을 받습니다.
첫 번째 인자로 index
를 넘겨줄경우 props.theme.palette[props.palette][tone]
을 반환하며,
key를 넘겨줄경우 props.theme.palette[key][tone]
을 반환합니다.
import styled, { ThemeProvider } from 'styled-components'
import { palette } from 'styled-tools'
const theme = {
palette: {
primary: ['#1976d2', '#2196f3', '#71bcf7', '#c2e2fb'],
secondary: ['#c2185b', '#e91e63', '#f06292', '#f8bbd0']
}
}
const Button = styled.button`
color: ${palette(1)}; // props.theme.palette[props.palette][1]
color: ${palette('primary', 1)}; // props.theme.palette.primary[1]
color: ${palette('primary')}; // props.theme.palette.primary[props.tone || 0]
color: ${palette('primary', -1)}; // props.theme.palette.primary[3] 뒤에서 1번째 index
color: ${palette('primary', 10)}; // props.theme.palette.primary[3]
color: ${palette('primary', -10)}; // props.theme.palette.primary[0]
color: ${palette('primary', 0, 'red')}; // props.theme.palette.primary[0] || red
`
;<ThemeProvider theme={theme}>
<Button palette="secondary" />
</ThemeProvider>
ifProp
ifProp(test: string | string[] | object, pass: any = "", fail: any = ""): PropsFn
첫 번째 인자로 test할 값을 받고 두 번째 인자로 test할 값이 props
에 존재할 때 반환할 값을 받습니다 마지막 인자로는 props
에 존재하지 않을 때 반환할 값을 받습니다.
첫 번째 인자로 배열과 객체를 넘겨줄 수 있는데 배열을 넘겨줄 경우, 배열 안의 모든 값이 다 props
에 존재하면 pass
값이 반환되고 존재하지 않으면 fail
값이 반환됩니다.
객체를 넘겨줄 경우, 객체의 property 값이 value 값인 데이터가 props
에 존재하면 pass
값이 반환되고 존재하지 않으면 fail
값이 반환됩니다.
import styled from 'styled-components'
import { ifProp, palette } from 'styled-tools'
const Button = styled.button`
background-color: ${ifProp('transparent', 'transparent', palette(0))};
color: ${ifProp(['transparent', 'accent'], palette('secondary'))};
font-size: ${ifProp(
{ size: 'large' },
'20px',
ifProp({ size: 'medium' }, '16px', '12px')
)};
`
// 해당 버튼과 동일
const Button2 = styled.button`
background-color: ${({ transparent, theme, palette }) =>
transparent ? 'transparent' : theme.palette[palette][0]};
color: ${({ transparent, accent, theme, palette }) =>
transparent && accent ? theme.palette.secondary : ''};
font-size: ${({ size }) =>
size === 'large' ? '20px' : size === 'medium' ? '16px' : '12px'};
`
ifNotProp
ifNotProp(test: string | string[] | object, pass: any = "", fail: any = ""): PropsFn
ifProp와 동일하지만 test할 값이 props
에 존재하지 않을 때 pass
값을 반환하고 존재할 때 fail
값을 반환합니다.
import styled from 'styled-components'
import { ifNotProp, palette } from 'styled-tools'
const Button = styled.button`
background-color: ${ifNotProp('transparent', 'transparent', palette(0))};
color: ${ifNotProp(['transparent', 'accent'], palette('secondary'))};
font-size: ${ifNotProp(
{ size: 'large' },
'20px',
ifNotProp({ size: 'medium' }, '16px', '12px')
)};
`
// 해당 버튼과 동일
const Button2 = styled.button`
background-color: ${({ transparent, theme, palette }) =>
!transparent ? 'transparent' : theme.palette[palette][0]};
color: ${({ transparent, accent, theme, palette }) =>
!(transparent && accent) ? theme.palette.secondary : ''};
font-size: ${({ size }) =>
size !== 'large' ? '20px' : size !== 'medium' ? '16px' : '12px'};
`
withProp
withProp(path: string | string[] | object, fn: function): PropsFn
첫 번째 인자로 path
를 받고 두 번째 인자로 함수를 받습니다.
props[path]
값을 조회한 뒤 해당 값을 두 번째 인자로 받은 함수의 인자로 넣어줘서 함수의 리턴값을 반환합니다.
import styled from 'styled-components'
import { withProp, prop } from "styled-tools";
const Button = styled.button`
border: ${withProp(prop("theme.primaryColor", "blue"), color => `1px solid ${color}`)};
font-size: ${withProp("theme.size", size => `${size + 1}px`)};
background: ${withProp(["foo", "bar"], (foo, bar) => `${foo}${bar}`)};
`;
// 해당 버튼과 동일
const Button2 = styled.button`
border: ${({theme}) => `1px solid ${theme.primaryColor || 'blue'}`};
font-size: ${({theme}) => `${theme.size}px`};
background: ${({foo, bar}) => `${foo}${bar}`};
`