언급하지 않아도 되는 기능이지만 css, sass 스타터들을 위해(나를 포함) 설명합니다. 매우매우 좋은 기능입니다.
자동 prefixing(auto-prefixing)이 무엇인가요?
당신의 css에 여러 브라우저에 동작할 수 있도록 자동으로 prefix를 해주는 것입니다.
display: flex;
flex-direction: row;
위 처럼 작성하더라도 아래와 같이 자동 prefixing 해줍니다.
-ms-flex: 1;
flex: 1 1;
display: -ms-flexbox;
display: flex;
-ms-flex-direction: row;
flex-direction: row;
'attrs'를 잊지 마세요.
그리고 'attrs'는 props
에 접근하여 사용할 수 있습니다.
const InputText = styled.input.attrs({
type: 'text',
placeholder: props => props.placeholder || 'Please fill',
})`
padding: 6px 12px;
`;
'attrs'를 사용하여 className
attribute를 사용할 수 있습니다.
그래서 css framework를 styled-components로 쉽게 변환할 수 있습니다.
const Button = styled.button.attrs({
className: 'btn btn-primary'
})``;
// With some dynamic props
const Button = styled.button.attrs({
className: `btn btn-primary btn-${props => props.size || 'medium'}`
})``;
<Button size="small" />
.btn{
background: whiteSmoke;
color: black;
width: 10rem;
font-size: 1rem;
...
&-primary{
background: red;
color: white;
...
}
&-small{
width: 5rem;
font-size: 0.75rem;
...
}
&-medium{
width: 7.5rem;
font-size: 0.85rem;
...
}
}
withComponent
를 통해서 component를 쉽게 바꿀 수 있습니다.
가령 button
을 a
component로 간단하게 변경할 수 있습니다.
const PrimaryButton = styled.button`
background-color: blue;
`;
const PrimaryLink = PrimaryButton.withComponent('a');
nested rules: 중괄호를 통한 하위 스타일 쉽게 접근 가능한 스타일 구문
media query: 반응형 스타일을 위한 스타일 구문
const MyBox = styled.div`
width: 500px;
height: 300px;
::before {
content: '';
}
::after {
content: '';
}
li::first-child {
content: '';
}
@media (max-width: 700px) {
background: palevioletred;
}
`;
css에서 하지 못했던 element의 부모요소에 접근가능합니다.
(매우 흥미로운 부분입니다.)
const Link = styled.a`
display: flex;
align-items: center;
padding: 5px 10px;
background: papayawhip;
color: palevioletred;
&:hover svg { ... } // {1}
`;
const Icon = styled.svg`
transition: fill 0.25s;
width: 48px;
height: 48px;
${Link}:hover & { // {2}
fill: rebeccapurple;
}
`;
{1} : <-- css에서는 이렇게 작성해야만 Link hover 시 자식요소인 svg에 접근가능합니다.
{2} : <-- styled-component에서는 Link를 하위요소인 svg에서 접근하여 hover와 같은 스타일을 줄 수 있습니다.
import styled, { ThemeProvider } from 'styled-components';
const theme = {
primaryColor: 'salmon',
fontFamily: 'Bebas',
};
const Button = styled.button`
background: ${props => props.theme.primaryColor}
font-family: ${props => props.theme.fontFamily}
`;
<ThemeProvider theme={theme}>
<Button />
{/* Or you can override */}
<Button theme={{ primaryColor: 'green' }} />
</ThemeProvider>
theme
을 통해서 style관리를 편하게 할 수 있습니다.
typescript 쓸 시에는 theme
타입은 DefaultTheme
으로 정의됩니다.
styled-components DefaultTheme
에 타입을 정의해두고 export하면 접근하여 사용할 수 있습니다.
declare module "styled-components" {
export interface DefaultTheme {
primaryColor: string;
secondaryColor: string;
...
}
}
import { DefaultTheme } from "styled-components";
export const theme: DefaultTheme = {
primaryColor: "#111111";
secondaryColor: "#333333";
...
}
styled-components의 css
helper와 polished
package를 이용하면 쉽게 구현가능합니다.
polished
는 styled-components에서 제공하고 있습니다.
가령 sass에서 사용되는 darken
,lighten
이 있습니다.
import { css } from 'styled-components';
const boxShadowMixin = css`
box-shadow: 0 0 0 rgba(0, 0, 0, 0.5);
`;
const boxShadowMixinFunc = (top, left, blur, color, inset = false) => {
return `box-shadow: ${inset ? 'inset' : ''} ${top}px ${left}px ${blur}px ${color};`;
}
const StyledComp = styled.div`
${boxShadowMixin}
${boxShadowMixinFunc(0, 0, 4, 'rgba(0, 0, 0, 0.5)')}
`;
&
는 &
만큼 자기자신의 className을 생성합니다. 더 많이 사용할 수록 style 우선순위는 높아집니다.// Override Existing style
const MyStyledBox = styled(AlreadyStyledComponent)`
&&& {
color: palevioletred;
font-weight: bold;
}
`;
// Became
.MyBox.MyBox.MyBox {
color: palevioletred;
font-weight: bold;
}
// Override Inline style
const MyStyledComponent = styled(InlineStyledComponent)`
&[style] {
font-size: 12px !important;
color: blue !important;
}
`;
간단한 조건문을 넣을 때 좋은 snippet입니다.
background-color: ${props =>
(props.type === 'primary' && 'blue') ||
(props.type === 'danger' && 'red') ||
(props.type === 'warning' && 'yellow') ||
}
react typescript에서 styled-components로 props 사용하려면 type을 정의해주어야 합니다.
const Button = styled.button<{isPrimary: boolean}>`
background: ${props => props.isPrimary ? 'red' : 'white'};
`;
<Button isPrimary={true} />
그런데 위와 같은 camelCase 변수명으로 작성을 하게 되면 아래와 같은 warning이 나타난다.
React does not recognize the
isPrimary
prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercaseisPrimary
instead. If you accidentally passed it from a parent component, remove it from the DOM element.
props는 React Node를 거쳐서 오기 때문에 DOM 요소로 인식되거나 렌더링되는 것을 막아야 합니다.
styled-component docs에서는 위와 같은 것을 막기 위해서 몇가지 제공되는 것이 있습니다.
$
와 함께 변수명을 생성하여 사용합니다.
const Button = styled.button<{$isPrimary: boolean}>`
background: ${props => props.$isPrimary ? 'red' : 'white'};
`;
<Button $isPrimary={true} />
transient props 보다 더 동적이고 세분화된 방법입니다.
많은 hoc components들이 함께 compose되는 상황이고 같은 prop name을 공유해야되는 경우에 사용하기 좋습니다.
withConfig
에 shouldForwardProp
를 통해 사용합니다.
shouldForwardProp
기능은 Array.filter
와 유사합니다.
const Comp = styled('div').withConfig({
shouldForwardProp: (prop, defaultValidatorFn) =>
!['hidden'].includes(prop)
&& defaultValidatorFn(prop),
}).attrs({ className: 'foo' })`
color: red;
&.foo {
text-decoration: underline;
}
`;
render(
<Comp hidden draggable="true">
Drag Me!
</Comp>
);
Hello, I enjoy reading all of your article. I like to write a little comment to support you.JOKER123