-
Notifications
You must be signed in to change notification settings - Fork 0
styled components
(์์ฑ์: AEJIJEON)
CSS-in-JS styling์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ํ์กดํ๋ CSS in JS ๊ด๋ จ ๋ฆฌ์กํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.(emotion, styled-jsx...)
cssํ์ผ์ ์์ฑํ์ง ์๊ณ javascript ์ฝ๋ ๋ด์์ ์ผ๋ฐ css๋ก ์ปดํฌ๋ํธ์ ์คํ์ผ์ ์ง์ ํ ์ ์๋ค.
styled-components ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ๋จผ์ Tagged Template Literal์ด๋ผ๋ ๋ฌธ๋ฒ์ ์ดํด๋ณด์.
Template Literal๋ฌธ๋ฒ์ ๋ฌธ์์ด ์กฐํฉ์ ์ฝ๊ฒ ํ ์ ์๊ฒ ํด์ฃผ๋ ES6 ๋ฌธ๋ฒ์ผ๋ก ์์ฃผ ์ฌ์ฉ๋๋ ๋ฌธ๋ฒ์ด๋ค.
console.log(`hello ${user}`);
์์ ๊ฐ์ด ๋ฐฑํฑ(``)์ ์ฌ์ฉํด์ ๋ฌธ์์ด ์์ javascript values(variable, object, function, etc.)๋ฅผ ํฌํจ์ํฌ ์ ์๋ค.
๊ทธ๋ ๋ค๋ฉด Tagged Template Literal ๋ฌธ๋ฒ์ ๋ฌด์์ผ๊น?
Tagged Template Literal์ Template Literal์ ์ด์ฉํ์ฌ ํจ์์ ์ธ์๋ฅผ parsing ํ์ฌ ๋๊ฒจ์ฃผ๋ ๊ฒ์ด๋ค. Template Literal์ ์ฌ์ฉํ๋ฉด์ ๋ฐฑํฑ ์์ ๋ฃ์ด์ค javascript values๋ฅผ ์กฐํํ๊ณ ์ถ์ ๋ Tagged Template Literal ๋ฌธ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
์์๋ฅผ ์ดํด๋ณด์.
const var1 = "first";
const var2 = "second";
function approachToVars(texts, ...values) {
//ํ๋ผ๋ฏธํฐ์ rest ๋ฌธ๋ฒ ์ฌ์ฉ
console.log(texts, values); // [ 'blabla ', ' and ', ' blabla' ] [ 'first', 'second' ]
}
approachToVars`blabla ${var1} and ${var2} blabla`; // Template Literal๋ฅผ ์ด์ฉํ์ฌ
// ํจ์์ ์ธ์๋ฅผ parsing(${} ๋ถ๋ถ ๋ถ๋ฆฌ)ํ์ฌ ๋๊ฒจ์ค
function sample(texts, ...ftns) {
console.log(texts);
console.log(ftns);
ftns.forEach((ftn) => ftn());
}
//${}์ ํตํ์ฌ ํจ์๋ฅผ ๋๊ฒจ์ฃผ๋ฉด ํด๋น ํจ์๋ฅผ sampleํจ์์์ ํธ์ถ์ํฌ ์ ์์
sample`
์ ๋ชฉ: ${() => console.log("์ ๋ชฉ
๋ด์ฉ" >")}
๋ด์ฉ: ${() => console.log("๋ด์ฉ")}
`;
// ์ถ๋ ฅ:
// ["\n ์ ๋ชฉ: ", "\n ๋ด์ฉ: ", "\n"]
// [ [Function (anonymous)], [Function (anonymous)] ]
// ์ ๋ชฉ
// ๋ด์ฉ
styled-components์์๋ ์ด๋ฌํ Tagged Template Literal ๋ฌธ๋ฒ์ ์ฌ์ฉํด์ javascript values์ ํจ๊ป stylingํ ์ ์๊ณ , ๋ค์ ์๋ ์์ ์ฝ๋์ ๊ฐ์ด ์ปดํฌ๋ํธ์ props๋ฅผ ์ฝ์ด์์ styling ๊ฐ๋ฅํ๋ค.
//component์ props๋ฅผ ์ฝ์ด์ด
const styledDev = styled`
background: ${(props) => props.color};
`;
npm install โsave styled-components
- ์ฝ๋
import React from "react";
import styled from "styled-components";
const Circle = styled.div`
width: 10rem;
height: 10rem;
background: blue;
border-radius: 50%;
`;
function App() {
return <Circle />;;
}
export default App;
์ ์ฝ๋์์์ฒ๋ผ javascript ํ์ผ์์ ์คํ์ผ์ ์ ๋ ฅํจ๊ณผ ๋์์ ํด๋น ์คํ์ผ์ ๊ฐ์ง ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์๊ณ , styled.input, styled.button๊ณผ ๊ฐ์ด html tag๋ค์ ๊ฐ์ง๊ณ ์คํ์ผ๋งํ ์ ์๋ค.
- ํ๋ฉด
styled-components ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ๊ณตํ๋ ์ฌ๋ฌ api๋ค์ ์ดํด๋ณด์.
์คํ์ผ์ ์ ํ tagname๋ component๋ฅผ ์ธ์๋ก ์ ๋ฌ(optional)ํ๋ฉด ์ผ๋ฐ css์ฝ๋๋ฅผ ํฌํจํ๋ Tagged Template literal์ ๋ฐ์์ StyledComponent๋ฅผ ๋ง๋ค์ด์ฃผ๋ ํจ์๋ฅผ return ํด ์ค
- ์ฝ๋
import React from "react";
import styled from "styled-components";
// styled.button์ styled(button)์ ์ฝ์ด
// button tag๋ฅผ ๊ฐ์ง๊ณ ์คํ์ผ๋งํ StyleComponent๋ฅผ ๋ง๋ฆ
const Button = styled.button`
background: palevioletred;
border-radius: 3px;
border: none;
color: white;
`;
// ์์์ ๋ง๋ Button ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ง๊ณ ์คํ์ผ๋ง
// ๊ธฐ์กด Button ์ปดํฌ๋ํธ์ ์คํ์ผ์ ์๋ก์ด ์คํ์ผ๋ก ๋ฎ์
const RedButton = styled(Button)`
background: red;
`;
function App() {
return (
<>
<Button>Default Button</Button>
<RedButton>Red Button</RedButton>
</>
);
}
export default App;
- ํ๋ฉด
(case 1)styled ํจ์์์ ๊ตฌํํ css์ฝ๋์์
- example of case 1
import styled, { css } from "styled-components";
const Circle = styled.div`
width: 5rem;
height: 5rem;
background: red;
border-radius: 50%;
${(props) =>
props.huge &&
css`
width: 10rem;
height: 10rem;
`}
`;
function App() {
return <Circle />;
}
export default App;
Circle component์ props๋ฅผ ๋๊ฒจ์ฃผ์ด props๋ฅผ ๊ฐ์ง๊ณ ์คํ์ผ๋งํด์ฃผ์๋ค. ์์ ๊ฐ์ด css ํจ์๋ฅผ ์ฌ์ฉํด์ผ ๊ทธ ์คํ์ผ ๋ด๋ถ์์๋ ๋ค๋ฅธ props๋ฅผ ์กฐํํ ์ ์๊ฒ ๋๋ค.
- example of case 2
import styled, { css } from "styled-components";
const colorStyles = css`
${({ color }) => {
return css`
background: ${color};
`;
}}
`;
const Circle = styled.div`
width: 5rem;
height: 5rem;
${colorStyles};
border-radius: 50%;
${(props) =>
props.huge &&
css`
width: 10rem;
height: 10rem;
`}
`;
function App() {
return <Circle />;;
}
export default App;
styled-components์์ ์ ๊ณตํ๋ ํ ๋ง๋ฅผ ์ํ (helper) ์ปดํฌ๋ํธ์ด๋ค. styled-components๋ก ๋ง๋๋ ๋ชจ๋ ์ปดํฌ๋ํธ์์ ์กฐํํ์ฌ ์ฌ์ฉํ ์ ์๋ ์ ์ญ์ ์ธ ๊ฐ(theme)์ ์ค์ ํ ์ ์๋ค.
- ์์
function App() {
return (
<ThemeProvider
theme={{
palette: {
blue: "#228be6",
gray: "#495057",
pink: "#f06595",
},
}}
>
BUTTON>
</ThemeProvider>
);
}
ThemeProvider ์ปดํฌ๋ํธ์ theme props๋ก object๋ฅผ ์ ๋ฌํ๋ฉด ThemeProvider ๋ด๋ถ์ ๋ ๋๋ง๋ styled components์์ ๋ ๋๋ง ๋ ์กฐํํ์ฌ ์ฌ์ฉํ ์ theme์theme prop๊ฐ ๋ด๋ถ์ prop์ด ๋ ๋๋ง ๋ ์ปดํฌ๋ํธ๋ค์๊ฒ ์๋์ผ๋ก ์ ๋ฌ๋จ) *์ฃผ์ ThemeProvider ๋ด๋ถ๋ ํ๋์ ๋ฆฌ์กํธ ์๋ฆฌ๋จผํธ๋ก ๊ฐ์ธ์ ธ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ด๋ถ์ ์ฌ๋ฌ components๋ฅผ ๋ ๋๋ง ์ <></> ์ผ๋ก ๊ฐ์ธ์ฃผ์ด์ผ ํ๋ค.
- theme ์กฐํ ์์
const StyledButton = styled.button`
/_ ํฌ๊ธฐ _/
/_ ์์ _/
${(props) => {
const selected = props.theme.palette.blue;
return css`
background: ${selected};
&:hover {
background: ${lighten(0.1, selected)};
}
&:active {
background: ${darken(0.1, selected)};
}
`;
}}
/_ ๊ธฐํ _/
`;
ThemeProvider ๋ด๋ถ๋ ํ๋์ ๋ฆฌ์กํธ ์๋ฆฌ๋จผํธ๋ก ๊ฐ์ธ์ ธ ์์ด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ด๋ถ์ AppBlock ๊ณผ Dialog components๋ฅผ ๋ ๋๋ง ์ <> ์ผ๋ก ๊ฐ์ธ์ฃผ์ด์ผ ํจ
์ ๋๋ฉ์ด์
์ ๋ํ keyframes๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ฌ์ฉ๋๋ method์ด๋ค.
keyframes๋ฅผ ํฌํจํ๊ณ ์๋ TaggedTemplateLiteral์ ์ธ์๋ก ๋ฐ์์ Keyframes model์ returnํด์ค๋ค.
๋ค์ ์์๋ฅผ ์ดํด๋ณด์.
import styled from "styled-components";
const FadeInButton = styled.button`
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
animation: 5s fadeIn ease-out;
width: 100px;
height: 20px;
`;
function App() {
return <FadeInButton />;;
}
export default App;
์ด์ฒ๋ผ keyframes method๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ ๋๋ฉ์ด์
์ ์ถ๊ฐํ ์ปดํฌ๋ํธ์ TaggedTemplateLiteral์ ์ผ๋ฐ css ์ฝ๋๋ก keyframes๋ฅผ ์ ์ํด์ ์ฌ์ฉํ ์ ์๋ค.
ํ์ง๋ง ๋์ผํ keyframes๋ฅผ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์๋ ์ฌ์ฉํ ๊ฒฝ์ฐ ์ค๋ณต๋ ์ฝ๋๋ฅผ ์์ฑํด์ผ ํ๋ค.
const fadeIn = css`
@keyframes identifier {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
`;
const FadeInButton = styled.button`
${fadeIn}
animation: 5s identifier ease-out;
width: 100px;
height: 20px;
`;
์ด ์ฝ๋์์๋ fadeIn์ด๋ผ๋ css ์ฝ๋๋ฅผ ๋ง๋ค์ด์ ์ฌ๋ฌ ์ปดํฌ๋ํธ์ ํฌํจ์์ผ์ ์ฌ์ฉํ ์ ์์ง๋ง animation property์ ํด๋น keyfremes์ identifier์ ๋ฐ๋ก ๋ช ์ํด์ค์ผ ํ๋ค.
import styled, { keyframes } from "styled-components";
const fadeIn = keyframes`
0% {
opacity: 0;
}
100% {
opacity: 1;
}
`;
const FadeInButton = styled.button`
animation: 1s ${fadeIn} ease-out;
`;
function App() {
return <FadeInButton />;
}
export default App;
์ด์ ๊ฐ์ด keyframes method๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด keyframes model์ ์ฌ๋ฌ styled components์์ ์ฌ์ฉํ ์ ์๊ณ ์ด์ ์์์ ๊ฐ์ด keyframes์ identifier์ ๋ฐ๋ก ๋ช ์ํด์ค ํ์๊ฐ ์๊ฒ ๋๋ค.
styled components ์์ ์๋ h3, p์ ๊ฐ์ ํ๊ทธ๋ค์ ์คํ์ผ๋งํ ๋ ๋ฐ๋ก ๋ฐ๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด์ ์คํ์ผ๋ง ํ์ง ์๊ณ styled-components์์ Nested CSS ๋ฌธ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
const Block = styled.div`
width: 100rem;
height: 100rem;
// {} ์์ styling ์ถ๊ฐ...
h3 {
}
p {
}
`;
styled-components ์ฌ์ฉ ์์ ๋ณด๋ฌ๊ฐ๊ธฐ(codesandbox)
(์ฝ๋์ ์ฃผ์ ๋ฌ์๋จ์ต๋๋ค. ์ฒ์ฒํ ์ฝ์ด๋ณด๋ฉด styled-components์ ๋ํด ์ ์ดํดํ ์ ์์ ๊ฒ๋๋ค.)
"๋ฒจ๋กํผํธ์ ํจ๊ปํ๋ ๋ชจ๋ ๋ฆฌ์กํธ", 2021๋
04์ 25์ผ ์ ์, https://react.vlpt.us/styling/03-styled-components.html
https://styled-components.com/docs/api#primary