CSS-in-JS - The State of CSS 2022์์
์ฌ์ฉ ์์๊ฐ ์ ์ผ ๋์ Styled-Component์ ์ฌ์ฉ๋ฒ์ ์์๋ณด์๐จ
โท Styled Components ์ค์น
// with npm
$ npm install --save styled-components
// with yarn
$ yarn add styled-components
โท package.json์ ์ฝ๋๋ฅผ ์ถ๊ฐ
// ์๋์ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ฉด ์ฌ๋ฌ ๋ฒ์ ์
// Styled Components๊ฐ ์ค์น๋์ด ๋ฐ์ํ๋ ๋ฌธ์ ๋ฅผ ์ค์ฌ์ค๋ค.
{
"resolutions": {
"styled-components": "^5"
}
}
โท import ํ๊ธฐ
import styled from "styled-components"
๋ฐ์ดํ๊ฐ ์๋ ๋ฐฑํฑ(`)์ ์ฌ์ฉํ๋ค.
import styled from "styled-components";
// Styled Components๋ก ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ณ
const BlueButton = styled.button`
background-color: blue;
color: white;
`;
export default function App() {
// React ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฏ์ด ์ฌ์ฉํ๋ฉด ๋๋ค.
return <BlueButton>Blue Button</BlueButton>;
}
๊ธฐ์กด ์ปดํฌ๋ํธ๋ฅผ ์ฌํ์ฉํ์ฌ ์๋ก์ด ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์๋ค.
import styled from "styled-components";
const BlueButton = styled.button`
background-color: blue;
color: white;
`;
//๋ง๋ค์ด์ง ์ปดํฌ๋ํธ๋ฅผ ์ฌํ์ฉํด ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค ์ ์๋ค.
const BigBlueButton = styled(BlueButton)`
padding: 15px;
margin-top: 15px;
`;
//์ฌํ์ฉํ ์ปดํฌ๋ํธ๋ฅผ ์ฌํ์ฉํ ์๋ ์๋ค.
const BigRedButton = styled(BigBlueButton)`
background-color: red;
`;
export default function App() {
return (
<>
<BlueButton>Blue Button</BlueButton>
<br />
<BigBlueButton>Big Blue Button</BigBlueButton>
<br />
<BigRedButton>Big Red Button</BigRedButton>
</>
);
}
ํ ํ๋ฆฟ ๋ฆฌํฐ๋ด ๋ฌธ๋ฒ ${ }์ผ๋ก JavaScript ์ฝ๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
Props๋ก ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ ์ฌ์ฉํ ์ ์๋ค.
import styled from "styled-components";
export default function App() {
return (
<>
<Button1>Button1</Button1>
<Button1 skyblue>Button1</Button1>
</>
);
}
// ๋ฐ์์จ prop์ ๋ฐ๋ผ ์กฐ๊ฑด๋ถ ๋ ๋๋ง์ด ๊ฐ๋ฅํ๋ค.
const Button1 = styled.button`
background: ${(props) => (props.skyblue ? "skyblue" : "white")};
`;
Props ๊ฐ์ผ๋ก ๋ ๋๋ง๋ ๊ฐ๋ฅํ๋ค.
๋๋
import styled from "styled-components";
// ๋ฐ์์จ prop ๊ฐ์ ๊ทธ๋๋ก ์ด์ฉํด ๋ ๋๋งํ ์๋ ์๋ค.
const Button1 = styled.button`
background: ${(props) => (props.color ? props.color : "white")};
`;
// ๋ค์๊ณผ ๊ฐ์ ํ์์ผ๋ก๋ ํ์ฉํ ์ ์๋ค.
const Button2 = styled.button`
background: ${(props) => props.color || "white"};
`;
export default function App() {
return (
<>
<Button1>Button1</Button1><br />
<Button1 color="orange">Button1</Button1>
<Button1 color="tomato">Button1</Button1>
<br />
<Button2>Button2</Button2>
<Button2 color="pink">Button2</Button2>
<Button2 color="turquoise">Button2</Button2>
</>
);
}
// createGlobalStyle ๊ฐ์ ธ์ค๊ธฐ
import { createGlobalStyle } from "styled-components";
// ์คํ์ผ ์์ฑํ๊ธฐ
const GlobalStyle = createGlobalStyle`
button {
padding : 5px;
margin : 2px;
border-radius : 5px;
}
`
// <GlobalStyle> ์ปดํฌ๋ํธ๋ฅผ ์ต์์ ์ปดํฌ๋ํธ์์ ์ฌ์ฉ
function App() {
return (
<>
<GlobalStyle />
<Button>์ ์ญ ์คํ์ผ ์ ์ฉํ๊ธฐ</Button>
</>
);
์ปดํฌ๋ํธ๋ก ๋ง๋ค์ด์ ์ฌ๋ ค๋ ๋จ
import { createGlobalStyle } from 'styled-components';
import { useLocation } from 'react-router-dom';
function BackgroundColor() {
const { pathname } = useLocation();
let background;
switch (pathname) {
case '/':
background = '#EBEEFF';
break;
default:
background = '#FFF';
}
return <GlobalStyled $background={background} />;
}
export default BackgroundColor;
const GlobalStyled = createGlobalStyle<{ $background: string; }>`
body {
background: ${({ $background }) => $background || '#FFF'};
}
@media all and (max-width: 805px) {
body {
background: #FFF;
}
}
`;
&:hover์ ์คํ์ผ์ ์์ฑํ๋ฉด ๋๋ค.
โ๏ธ์ฐธ๊ณ ) &๋ ํ์ฌ์ ์์๋ฅผ ๋ปํ๋ค.
const Button1 = styled.button`
color: ${(props) => props.color || "white"};
// ํ์ฌ ์์์ ๋ง์ฐ์ค๊ฐ ์ฌ๋ผ๊ฐ ๋
&:hover {
background: purple;
color: white;
}
`;
&(ํ์ฌ ์์) ์ฌ์ฉ๋ฒ
&:hover // ํ์ฌ ์์์ ๋ง์ฐ์ค๊ฐ ์ฌ๋ผ๊ฐ ๋
& ~ & // ํ์ฌ ์์์ ๋ฐ๋ก ์์ ์๋์ง๋ง ํ์ ์์์ผ ๋
& + & // ํ์ฌ ์์์ ๋ฐ๋ก ์ ํ์ ์์์ผ ๋
&.something // ํ์ฌ ์์๊ฐ something์ด๋ผ๋ ํด๋์ค๋ฅผ ๊ฐ๊ณ ์์ ๋
.something & // something์ด๋ผ๋ ํด๋์ค๋ฅผ ๊ฐ์ง ์น๊ตฌ ์์ ์์ ๋
attributes๋ฅผ ์ฝ์ ํ๊ธฐ ์ํ ๋ฉ์๋์ด๋ฉฐ 1๊ฐ์ ๊ฐ์ฒด ํ์ arg๋ฅผ ๋ฐ๋๋ค.
html tag๊ฐ ๊ฐ์ง๊ณ ์๋ ๊ณ ์ ์ attributes๋ฅผ ๋ฐ๋ณต์ ์ผ๋ก ์ฌ์ฉํ์ง ์๊ธฐ ์ํด ๋ง๋ค์ด์ก๋ค.
(ex. <input type="radio" />๋ฅผ ๋ง๋ค ๋ attrs({ type: radio })๋ฅผ ์ฌ์ฉ)
export const ModalView = styled.div.attrs((props) => ({
// attrs ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ์๋์ ๊ฐ์ด div ์๋ฆฌ๋จผํธ์ ์์ฑ์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
role: "dialog",
}))`
border-radius: 10px;
background-color: #ffffff;
width: 400px;
...
`;
input ์์
// ์์ฉ1
const Input = styled.input.attrs((props) => ({
cursor: props.pointer ? "pointer" : "null",
}))`
cursor: ${({ cursor }) => cursor};
`;
-----
// ์์ฉ2
const Input = styled.input.attrs((props) => ({
cursor: props.pointer ? "pointer" : "null",
transparent: props.transparent ? "transparent" : "null",
}))`
cursor: ${({ cursor }) => cursor};
caret-color: ${({ transparent }) => transparent};
`;
import "./styles.css";
import styled, { createGlobalStyle } from "styled-components";
export default function App() {
return (
<>
<GlobalStyle />
<Button1 color="black">
Practice!
</Button1>
</>
);
}
const GlobalStyle = createGlobalStyle`
button {
padding : 5px;
margin : 2px;
border-radius : 5px;
}
`;
const Button1 = styled.button`
color: ${(props) => props.color || "white"};
&:hover {
background: purple;
color: white;
}
`;
โ ์ฐธ๊ณ
ํน์ง | ์ฅ์ | ๋จ์ | |
---|---|---|---|
CSS | ๊ธฐ๋ณธ์ ์ธ ์คํ์ผ๋ง ๊ธฐ๋ฒ | ์ผ๊ด๋ ํจํด์ ๊ฐ๊ธฐ ์ด๋ ค์, !important์ ๋จ์ฉ | |
SASS | ํ๋ก๊ทธ๋๋ฐ ๋ฐฉ๋ฒ๋ก ์ ๋์ ํ์ฌ, ์ปดํ์ผ๋ CSS๋ฅผ ๋ง๋ค์ด๋ด๋ ์ ์ฒ๋ฆฌ๊ธฐ | ๋ณ์/ํจ์/์์ ๊ฐ๋ ์ ํ์ฉํ์ฌ ์ฌ์ฌ์ฉ ๊ฐ๋ฅ, CSS์ ๊ตฌ์กฐํ | ์ ์ฒ๋ฆฌ ๊ณผ์ ์ด ํ์, ๋๋ฒ๊น ์ ์ด๋ ค์์ด ์์. ์ปดํ์ผํ CSS ํ์ผ์ด ๊ฑฐ๋ํด์ง |
BEM | CSS ํด๋์ค๋ช ์์ฑ์ ์ผ๊ด๋ ํจํด์ ๊ฐ์ ํ๋ ๋ฐฉ๋ฒ๋ก | ๋ค์ด๋ฐ์ผ๋ก ๋ฌธ์ ํด๊ฒฐ, ์ ์ฒ๋ฆฌ ๊ณผ์ ๋ถํ์ | ์ ํ์์ ์ด๋ฆ์ด ์ฅํฉํ๊ณ , ํด๋์ค ๋ชฉ๋ก์ด ๋๋ฌด ๋ง์์ง |
Styled-Component | ์ปดํฌ๋ํธ ๊ธฐ๋ฐ์ผ๋ก CSS๋ฅผ ์์ฑํ ์ ์๊ฒ ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ | CSS๋ฅผ ์ปดํฌ๋ํธ ์์ผ๋ก ์บก์ํ, ๋ค์ด๋ฐ์ด๋ ์ต์ ํ๋ฅผ ์ ๊ฒฝ ์ธ ํ์๊ฐ ์์ | ๋น ๋ฅธ ํ์ด์ง ๋ก๋์ ๋ถ๋ฆฌํจ |