์์๋ณด๊ธฐ ์ ์
Styled Components์์ด css๋ฅผ ๋ง๋ค์ด ๋ณด์
function App() {
return (
<div style={{ display: "flex" }}>
<div style={{ backgroundColor: "teal", width: 100, height: 100 }}></div>
<div style={{ backgroundColor: "tomato", width: 100, height: 100 }}></div>
</div>
);
}
์ด ๋ฐฉ์์ ๋จผ์ div๋ฅผ ์์ฑํ ๋ค์
์คํ์ผ์ ์ ์ฉ์์ผฐ๋ค
๊ทธ๋ฆฌ๊ณ ๊ฐ๊ฐ div ๋ฅผ ๋ค์ฌ๋ค๋ด์ผ์ง๋ง,
์ด๋ค ์ญํ ๊ณผ css๊ฐ ์ ์ฉ๋์๋์ง ์ ์ ์๋ค
๋จผ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํด์ค๋ค
npm i styled-components
๋ค์, import๋ฅผ ํด์ ์ฌ์ฉํ ์ค๋น๋ฅผ ํ๋ค
import styled from "Styled-components"
Styled Components๋ฅผ ์ฌ์ฉํ๋ฉด,
๋ชจ๋ ์คํ์ผ์ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ด์ ์ ๋ฏธ๋ฆฌ ์ปดํฌ๋ํธ์ ํฌํจ์ด ๋๋ค.
const ์๋ช
= styled.ํ๊ทธ ` css `
์ ๋ฐฉ์์ ํ ๋๋ก
์ด์ ์ ์์ฑํ ๊ธฐ๋ณธ css ๋ฅผ ๋์ฒดํด๋ณด์
// <div style={{ display: "flex" }}>
const Father = styled.div`
display: flex;
`;
// <div style={{ backgroundColor: "teal", width: 100, height: 100 }}></div>
const BoxOne = styled.div`
background-color: teal;
width: 100px;
height: 100px;
`;
const BoxTwo = styled.div`
background-color: tomato;
width: 100px;
height: 100px;
`;
const Text = styled.div`
color: white;
`;
function App() {
return (
<Father>
<BoxOne>
<Text> Hello</Text>
</BoxOne>
<BoxTwo />
</Father>
);
}
์ด ๋ฐฉ์์ ์ฅ์
ํ์ฌ ๋ฐ์ค 1๊ณผ 2 ๋ ์์๋ง ๋ค๋ฅด๋ค
ํ์ง๋ง ๋์ผ ์ฝ๋๋ฅผ ์์ ๋๋ฌธ์ 2๋ฒ ์ ๊ณ ์๋ค
์ด๋ฐ ๊ฒฝ์ฐ์๋, props ๋ฅผ ์ฌ์ฉํด์ ์ปดํฌ๋ํธ ํ์ฅ์ด ๊ฐ๋ฅํ๋ค
์คํ์ผ์ปดํฌ๋ํธ ์ ์ธ ๋ถ๋ถ์ด ์๋,
์ฌ์ฉ ๋ถ๋ถ์์ ๋ณ์๋ฅผ ์ ๋ฌํด์ฃผ๋ ๋ฐฉ์์ด๋ค
๋จผ์ ์ ์ธ ๋ถ๋ถ์์ ๋ณ๊ฒฝํ๊ณ ์ถ์ ๋ฐ์ดํฐ๋ฅผ ๋ณ์๋ก ์ ์ธํด์ฃผ๊ณ
ํธ์ถ ๋ถ๋ถ์์ ๋ณ์๋ฅผ props๋ก ์ ๋ฌํด์ฃผ๋ฉด ๋๋ค
const Box = styled.div`
background-color: ${(props) => props.bgColor};
width: 100px;
height: 100px;
`;
function App() {
return (
<Father>
<Box bgColor="teal" />
<Box bgColor="tomato" />
</Father>
);
}
๋ง์ฝ Box ์ ๋์ผํ ์คํ์ผ์ ๊ฐ์ง ์์ ๋ง๋ค๊ณ ์ถ์ผ๋ฉด ์ด๋ป๊ฒ ํ ๊น?
ํ๋ ๊ทธ๋๋ก ๋ง๋ค๋ฉด ๊ฐ๋จํ์ง๋ง,
์ฝ๋๊ฐ ์ค๋ณต๋๊ณ ์๋ค
const Box = styled.div`
background-color: ${(props) => props.bgColor};
width: 100px;
height: 100px;
`;
const Circle = styled.div`
background-color: ${(props) => props.bgColor};
width: 100px;
height: 100px;
border-radius: 50px;
`;
์ด ๋ ์ฌ์ฉ๊ฐ๋ฅ ํ ๋ฐฉ์์ด
์คํ์ผ ์ปดํฌ๋ํธ ์์ฒด๋ฅผ ๋ถ๋ฌ์ค๋ ํ์์ด๋ค
์์์ div ๋ฅผ ๋ถ๋ฌ ์ค๋ ๋์ ,
๋ง๋ค์ด ๋์ ์คํ์ผ ์ปดํฌ๋ํธ ์์ฒด๋ฅผ ๋ถ๋ฌ์ค๊ณ , css๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ๋๋ค
const Circle = styled(Box)`
border-radius: 50px;
`;
<Circle bgColor="tomato" />
import styled from "styled-components";
const Father = styled.div`
display: flex;
`;
const Box = styled.div`
background-color: ${(props) => props.bgColor};
width: 100px;
height: 100px;
`;
const Circle = styled(Box)`
border-radius: 50px;
`;
// const BoxTwo = styled.div`
// background-color: tomato;
// width: 100px;
// height: 100px;
// `;
const Text = styled.div`
color: white;
`;
export default function StyleComponents() {
return (
<Father>
<Box bgColor="teal" />
<Box bgColor="tomato" />
{/* <BoxTwo /> */}
<Circle bgColor="yellow">
<Text>Hello</Text>
</Circle>
</Father>
);
}
const Btn = styled.button`
color: white;
background-color: tomato;
border: 0;
border-radius: 15px;
`;
return (
<Father>
<Btn>Login </Btn>
<Btn>Logout </Btn>
</Father>
);
์คํ์ผ์ ์
ํ ๋ฒํผ ์ปดํฌ๋ํธ๋ฅผ ๋ฏธ๋ฆฌ ๋ง๋ค์ด ๋์๋ค
๊ทธ๋ฐ๋ฐ ๊ฐ์๊ธฐ
์คํ์ผ์ ๋์ผํ๊ฒ ์ ์งํ๋ฉด์,
๋ค๋ฅธ ํ๊ทธ, (div, Link ๋ฑ๋ฑ) ์ด ์ฌ์ฉํ๊ณ ์ถ์ผ๋ฉด ์ด๋ป๊ฒ ํ ๊น??
์ด ๋ ์ฌ์ฉํ๋๊ฒ as props์ด๋ค
as๋ฅผ ํตํด์ ํ๊ทธ๋ฅผ ์
๋ ฅํด์ฃผ๋ฉด ํด๋น ํ๊ทธ๋ก ๋ณ๊ฒฝ์ด ๋๋ค
a๋งํฌ๋ฅผ as๋ก ๋ณด๋ด์ฃผ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์
return (
<Father>
<Btn>Login </Btn>
<Btn as="a" href="/">Logout </Btn>
</Father>
);
buttonํ๊ทธ๋ฅผ ์ฌ์ฉํ๋ ์คํ์ผ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ์ง๋ง,
as๋ฅผ ํตํด์ aํ๊ทธ๋ก ๊ฐํธํ๊ฒ ๋ณ๊ฒฝํด์ค ์ ์๋ค.
aํ๊ทธ๋๊น ์ด๋๊ฒฝ๋ก๋ ๋ฐ๋ก ์จ์ฃผ๋ฉด๋๋ค
const Input = styled.input`
background-color: tomato;
`;
function App() {
return (
<Father as="header">
<Input required/>
<Input required/>
<Input required/>
<Input required/>
</Father>
);
}
๋ชจ๋ input์ required ๋ผ๋ ์์ฑ์ ์ถ๊ฐํ๊ณ ์ถ๋ค
๊ฐ๊ฐ์ input์ ๋ฃ์ด์ฃผ๋ฉด ๊ฐ๋จํ์ง๋ง, ์ด๊ฑด ๊ฐ๋ฐ์ ์ค๋ฝ์ง ๋ชปํ๋ค
attrs ๋ฅผ ํ์ฉํ๋ฉด,
ํ๊ทธ๋ก ์ ๋ฌ๋ ์์ฑ์ ๊ฐ์ง ์ค๋ธ์ ํธ๋ฅผ ์์ฑํ ์ ์๋ค
const Input = styled.input.attrs({ required: true, minLength: 10 })`
background-color: tomato;
`;
function App() {
return (
<Father as="header">
<Input />
<Input />
<Input />
<Input />
</Father>
);
}
์ด๋ ๊ฒ ๊ฐ์ฒด๋ฅผ ์ค์ ํด์ฃผ๋ฉด ์์์ ์ค์ ํ required๊ฐ ์ ๋ถ ๋์ผํ๊ฒ ๋ค์ด๊ฐ๋ค
, ๋ฅผ ํตํด์ ์ฌ๋ฌ๊ฐ์ง ์์ฑ์ ์ถ๊ฐํ ์๋ ์๋ค
์คํ์ผ์ปดํฌ๋ํธ์์ ์ ๋๋ฉ์ด์
์ ์ฌ์ฉํ๋ฌ๋ฉด
๋จผ์ keyframes ๋ฅผ import ํด์์ผํ๋ค
import { keyframes } from "styled-components"
๋ค์, ๋ฐ์์ animation ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด์ค๋ค
const animation = keyframes`
// css ์์ฑ
`
์์๋ค๊ฐ ๊ธฐ๋ณธ css ์ ๋๋ฉ์ด์ ์ ์ฃผ๋ฉด ๋๋ค
const animation = keyframes`
from {
transform: rotate(0);
}
to {
transform: rotate(360);
}
`
๊ทธ๋ฆฌ๊ณ ์ฌ์ฉํ๊ณ ์ถ์ ์คํ์ผ์ปดํฌ๋ํธ์
์คํ์ผ๋ก ๋ฃ์ด์ฃผ๋ฉด ๋๋ค
const Box = styled.div`
width: 200px;
height: 200px;
background-color: tomato;
animation: ${rotationAnimation} 1s linear infinite;
`;
๐ ์์ฑ๋ณธ
import styled, { keyframes } from "styled-components";
const rotationAnimation = keyframes`
0% {
transform: rotate(0deg);
border-radius: 0px;
}
50% {
transform: rotate(360deg);
border-radius: 100px;
}
100% {
transform: rotate(0deg);
border-radius: 0px;
}
`;
const Box = styled.div`
width: 200px;
height: 200px;
background-color: tomato;
animation: ${rotationAnimation} 1s linear infinite;
`;
export default function AnimationBox() {
return (
<div>
<Box />
</div>
);
}
<Box>
<span>๐ข</span>
</Box>
์คํ์ผ์ปดํฌ๋ํธ ์์ ๊ทธ๋ฅ ํ๊ทธ๊ฐ ๋ค์ด์๋ค
๊ทธ๋ฅ ํ๊ทธ๋ฅผ ์คํ์ผ์ปดํฌ๋ํธ์์
selector ๋ฌธ๋ฒ์ผ๋ก ์ ํํด์
์คํ์ผ ์ง์ ์ด ๊ฐ๋ฅํ๋ค
์ฆ, ๋ชจ๋ ์ปดํฌ๋ํธ๋ฅผ ์คํ์ผ์ปดํฌ๋ํธ๋ก ๋ง๋ค ํ์๊ฐ ์๋ ์ ์ด๋ค
const Box = styled.div`
...
justify-content: center;
align-items: center;
span {
font-size: 36px;
}
`;
&:active {
opacity: 0%;
}
selector ์์
span:hover ๊ฐ์ ๊ฒ์ ๋ ์ฝ๊ฒ ์ ์ฉ์์ผ์ฃผ๋ ๋ฌธ๋ฒ์ด๋ค
span:hover = &:hover
const Box = styled.div`
...
align-items: center;
span {
font-size: 36px;
&:hover {
font-size: 50px;
}
&:active {
opacity: 0%;
}
}
`;
import styled, { keyframes } from "styled-components";
const rotationAnimation = keyframes`
0% {
transform: rotate(0deg);
border-radius: 0px;
}
50% {
transform: rotate(360deg);
border-radius: 100px;
}
100% {
transform: rotate(0deg);
border-radius: 0px;
}
`;
const Box = styled.div`
width: 200px;
height: 200px;
background-color: tomato;
animation: ${rotationAnimation} 1s linear infinite;
display: flex;
justify-content: center;
align-items: center;
span {
font-size: 36px;
&:hover {
font-size: 50px;
}
&:active {
opacity: 0%;
}
}
`;
export default function AnimationBox() {
return (
<div>
<Box>
<span>๐ข</span>
</Box>
</div>
);
}
ํ์ฌ spanํ๊ทธ๋ก ์ฝ๋ฉํด๋์๋ค
๊ทธ๋ผ ๋ฆฌํด ๋ถ๋ถ์์ span ์ pํ๊ทธ๋ก ๋ณ๊ฒฝํ๋ค๋ฉด
์์์ selectํด๋์ ๊ฒ ๋ณ๊ฒฝ๋์ด ์๋ฌด๋ฐ css๋ ์ ์ฉ๋์ง ์๋๋ค
์ฆ, select ๋ถ๋ถ์ ๋ค์ p๋ก ๋ณ๊ฒฝํด์ฃผ์ด ๋ง์ถฐ์ค์ผ์ง ์ ์ฉ์ด ๋๋ค
์ด๋ฐ ๊ฒฝ์ฐ,
ํ๋์ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด์ ๋ฃ์ด๋ฒ๋ฆฌ๋ฉด ๋๋ค
๊ทธ๋ฆฌ๊ณ ์คํ์ผ์ปดํฌ๋ํธ์์๋
span ์๋ฆฌ์
${์๋ก๋ง๋ ์ปดํฌ๋ํธ๋ช
} ์ ๋ฃ์ด์ select ํด์ฃผ๋ฉด ๋๋ค
๊ทธ๋ฌ๋ฉด, ํด๋น ํ๊ทธ๊ฐ span ์ด๊ฑด p์ด๊ฑด ์ ์์๋๋๋ค
const Emoji = styled.span`
font-size : 36px
`
const Box = styled.div`
...
align-items: center;
${Emoji} {
&:hover {
font-size: 50px;
}
&:active {
opacity: 0%;
}
}
`;
export default function AnimationBox() {
return (
<div>
<Box>
<Emoji>๐ข</Emoji> ๐ ์ ์ฉ
</Box>
<Emoji>๐ฅ</Emoji> ๐ ๋ฏธ์ ์ฉ
</div>
);
}
Emoji ์ปดํฌ๋ํธ์ hover ์คํ์ผ์
๋ฐ๋์ box ์คํ์ผ์ปดํฌ๋ํธ ๋ด์์๋ง ์ ์ฉ์ด ๋๋ค
select๋ก ์ฐ์ด๋์๊ธฐ ๋๋ฌธ์ด๋ค
๋ฐ๋ผ์ ์ ์ฝ๋์ ๋๋ฒ์งธ ์ด๋ชจ์ง๋
36px์ ๊ฐ์ง์ง๋ง, hover๋ ์ ์ฉ๋์ง ์๋๋ค
๋คํฌ๋ชจ๋์์ ํ์ํ ๊ฒ์ ๋๊ฐ์ง ์ด๋ค
์ด ์ค, ์ฒซ๋ฒ์งธ์ธ theme์ ์์ธํ ์์๋ณด์
theme?
- ๋ชจ๋ ์์๋ค์ ๊ฐ์ง๊ณ ์๋ ํ๋์ ๊ฐ์ฒด
๊ฐ์ฅ ๋จผ์ theme provider ๋ฅผ indexํ์ผ์์ importํด์ค๋ค
๊ทธ๋ฆฌ๊ณ App ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ธ์ค๋ค
๊ทธ๋ฆฌ๊ณ ์์์ props ๋ก ๋ด๋ ค์ค๋ค
//index.js or main.js(in vite)
import { ThemeProvider } from "styled-components";
const darkTheme = {
textColor: "whitesmoke",
backgroundColor: "#111"
};
const lightTheme = {
textColor: "#111",
backgroundColor: "whitesmoke",
};
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ThemeProvider theme={darkTheme}>
<App />
</ThemeProvider>
</StrictMode>
);
ํ์ฌ ThemeProvider ์ ์์์ ๋ฃ์ด์คฌ๊ธฐ ๋๋ฌธ์
App ์ ์๋ ๋ชจ๋ ์ปดํฌ๋ํธ๋ค์ด ํด๋น ์์์ ์ ๊ทผ ํ ์ ์๋ค
์ฆ, ์์์ ์ง์ ํ theme ๊ฐ์ฒด์
textColor ๊ฐ๊ณผ
backgroundColor ๊ฐ์ ์ ๊ทผ์ด ๊ฐ๋ฅํด์ง๊ฒ์ด๋ค
(์ด๊ฑด ์๋ช
์ด๋ผ ์๋ฌด๊ฑฐ๋ ๊ฐ๋ฅ)
// App.js
const Title = styled.h1`
color : ${props => props.theme.textColor}
`
const Wrapper = styled.div`
background-color : ${props => props.theme.backgroundColor}
`
์ด์ ๋ชจ๋ ๋ณ๊ฒฝ์ ํด์ฃผ๊ณ ์ถ์ผ๋ฉด
<ThemeProvider theme={darkTheme}> ์ด ๋ถ๋ถ์ props๋ฅผ
์์์ ์ ์ธํ lightTheme์ผ๋ก ๋ฐ๊ฟ์ฃผ๋ฉด ๋๋ค
์ฌ๊ธฐ์ ์กฐ์ฌํด์ผํ ์ ์ด
๋ฐ๋์ ๋ ํ
๋ง์ ํ๋กํผํฐ ์๋ช
์ด ๋์ผํด์ผํ๋ค๋ ์ ์ด๋ค