css-in-js는 2018년 이후 폭발적으로 성장하고 있다. 그 중 Styled-Components
는 npm 다운로드 수 기준으로 현재 가장 인기있는 css-in-js 라이브러리이다.
설치
npm install --save styled-components
공식 문서
https://styled-components.com/
// styled-components 라이브러리에서 import 해온 styled라는 객체를 이용합니다
// 아래와 같이 h1 태그를 만들어 Title이라는 스타일드 컴포넌트를 만들 수 있습니다
import styled from 'styled-components'
render(
<Wrapper>
<Title>
Hello World!
</Title>
</Wrapper>
);
// html 태그 이름 뒤 Tagged Templete 문법을 활용해 CSS 속성을 정의하고 있습니다
// 앞서 학습했던 Templete Literals 문법(``)의 확장이라고 생각해도 좋습니다 ([링크](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals))
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`;
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
render(
<div>
<Button>Normal</Button>
<Button primary width="100">Primary</Button>
</div>
);
// 만약 Button 컴포넌트에 전달된 props(width)가 200 미만(조건)이면
// 삼항연산자 true : "palevioletred"
// 삼항연산자 false : "white"
const Button = styled.button`
background: ${props => props.width < 200 ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
render(
<div>
<Button>Normal Button</Button>
<TomatoAnchorButton>Tomato Button</TomatoAnchorButton>
</div>
);
// The Button from the last section without the interpolations
const Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// A new component based on Button, but with some override styles
// Button의 속성을 상속 받아 새로운 anchor 태그를 생성
const TomatoAnchorButton = styled(Button.withComponent("a"))`
color: tomato;
border-color: tomato;
`;
가장 크게 체감할 수 있는 Pure CSS와 SASS의 차이라면 nesting 기능 유무에 있다. Styled Components 역시 해당 기능을 제공한다. 적절히 사용한다면 모든 컴포넌트를 스타일드 컴포넌트화 시키지 않더라도 충분히 스타일링할 수 있다.
render(
<>
<Thing>Hello world!</Thing>
<Thing>How ya doing?</Thing>
<Thing className="something">The sun is shining...</Thing>
<div>Pretty nice day today.</div>
<Thing>Don't you think?</Thing>
<div className="something-else">
<Thing>Splendid.</Thing>
</div>
</>
)
const Thing = styled.div`
color: blue;
&:hover {
color: red;
}
#id {
div {
background: orange;
}
}
.something-else & {
border: 1px solid;
}
`
render(
<>
<GlobalStyle />
<Thing>
I'm blue, da ba dee da ba daa
</Thing>
</>
)
const Thing = styled.div`
&& {
color: blue;
}
`
const GlobalStyle = createGlobalStyle`
${Thing} {
color: red;
}
`
import { css } from "styled-components"
const Navigation = styled.nav`
position: fixed;
left: 0;
top: 0;
right: 0;
${Sticky}
`;
const Sticky = css`
position: fixed !important;
background-color: white;
border-bottom: 1px solid rgba(0, 0, 0, 0.11);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.11);
transition: all 0.6s ease-in-out;
color: black;
`;
//
const RingVariant = (radius, stroke = "10") => css`
position: absolute;
border-radius: 50%;
height: ${radius * 2}px;
width: ${radius * 2}px;
border: ${stroke}px solid rgba(0, 0, 0, 0.5);
`;
render(
<div>
<Input placeholder="A small text input" />
<br />
<Input placeholder="A bigger text input" size="2em" />
</div>
);
const Input = styled.input.attrs(props => ({
// we can define static props
type: "password",
// or we can define dynamic ones
size: props.size || "1em",
}))`
color: palevioletred;
font-size: 1em;
border: 2px solid palevioletred;
border-radius: 3px;
/* here we use the dynamically computed prop */
margin: ${props => props.size};
padding: ${props => props.size};
`;
// Create the keyframes
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
// Here we create a component that will rotate everything we pass in over two seconds
const Rotate = styled.div`
display: inline-block;
animation: ${rotate} 2s linear infinite;
padding: 2rem 1rem;
font-size: 1.2rem;
`;
render(
<Rotate>< 💅🏾 ></Rotate>
);
npm install --save styled-components styled-reset
import * as React from 'react'
import { createGlobalStyle } from 'styled-components'
import reset from 'styled-reset'
const GlobalStyle = createGlobalStyle`
${reset}
/* other styles */
`
const App = () => (
<React.Fragment>
<GlobalStyle />
<div>Hi, I'm an app!</div>
</React.Fragment>
}
export default App