반응형
CSS-in-JS란?
자바스크립트 파일 안에서 CSS를 작성할 수 있는 방법이다.
자바스크립트의 상태 값을 공유하여 동적으로 스타일링을 하기 위해 등장한 패러다임이다.
인라일 스타일 이용 or 클래스 명으로 조건부 스타일링 <- 문제점이 있음
- (전자: 스타일 재사용 X, 후자: 클래스 이름 중복 문제)
CSS-in-JS의 장점
JS 파일 안에서 CSS 코드를 작성하기 때문에 CSS의 변수와 함수를 그대로 사용할 수 있다.
클래스 명이 해시 값으로 치환되기 때문에 클래스 이름의 중복 및 작명에 대한 걱정을 덜 수 있다.
현대 웹은 컴포넌트를 기반으로 발전하고 있으므로, 컴포넌트와 스타일을 하나의 파일에서 작성하는 CSS-in-JS는 모듈화가 수월해진다.
Styled Components
- CSS-in-JS에는 여러 종류의 라이브러리가 있는데, 2022년 기준 가장 많이 사용되는 라이브러리가
styled-components
이다.
설치
npm install styled-components
Styled Components 사용법 및 문법
const [컴포넌트명] = styled.[html태그]`
[부여하고자 하는 css속성]
`;
// 사용 예시
import styled from "styled-components";
const Father = styled.div`
display: flex;
`;
const BoxOne = styled.div`
background-color: teal;
width: 100px;
height: 100px;
`;
const BoxTwo = styled.div`
background-color: tomato;
width: 100px;
height: 100px;
`;
function App() {
return (
<Father>
<BoxOne />
<BoxTwo />
</Father>
);
}
export default App;
- vscode-styled-components 익스텐션 : styled-component css 자동완성 기능 제공
컴포넌트의 props 속성값에 따라 서로 다른 스타일 부여하기 - ${(props) => props.[props 속성 이름]}
import styled from "styled-components";
const Father = styled.div`
display: flex;
`;
const Box = styled.div`
background-color: ${(props) => props.bgColor};
width: 100px;
height: 100px;
`;
function App() {
return (
<Father>
<Box bgColor="teal" />
<Box bgColor="tomato" />
</Father>
);
}
export default App;
- 이 문법을 활용하면 중복되는 스타일 코드를 하나로 나타낼 수 있으므로 코드가 더욱 깔끔해진다.
컴포넌트 스타일 확장하기 - styled([컴포넌트])
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;
`;
function App() {
return (
<Father>
<Box bgColor="teal" />
<Circle bgColor="tomato" />
</Father>
);
}
export default App;
컴포넌트의 HTML 태그 재설정하기 - as
props
import styled from "styled-components";
const Father = styled.div`
display: flex;
`;
const Btn = styled.button`
color: white;
background-color: tomato;
border: 0;
border-radius: 15px;
`;
function App() {
return (
<Father as="header">
<Btn>Log In</Btn>
<Btn as="a" href="/">
Log In
</Btn>
</Father>
);
}
export default App;
<div id="root">
<header class="sc-dIfARi kqAazX">
<button class="sc-hHTYSt iKcUmj">Log In</button
><a href="/" class="sc-hHTYSt iKcUmj">Log In</a>
</header>
</div>
- 스타일은 그대로 두되, 컴포넌트의 태그를 바꾸고자 할 때
as
props를 활용한다.
컴포넌트의 HTML 태그에 속성 직접 추가하기 - styled.[태그].attrs({ [속성] })
import styled from "styled-components";
const Father = styled.div`
display: flex;
`;
const Input = styled.input.attrs({ required: true, minLength: 10 })`
background-color: tomato;
`;
function App() {
return (
<Father as="header">
<Input></Input>
<Input></Input>
<Input></Input>
<Input></Input>
<Input></Input>
</Father>
);
}
export default App;
<div id="root">
<header class="sc-fLcnxK hjukqa">
<input required="" class="sc-bBABsx iPtiKZ" minlength="10" /><input
required=""
class="sc-bBABsx iPtiKZ"
minlength="10"
/><input required="" class="sc-bBABsx iPtiKZ" minlength="10" /><input
required=""
class="sc-bBABsx iPtiKZ"
minlength="10"
/><input required="" class="sc-bBABsx iPtiKZ" minlength="10" />
</header>
</div>
styled-components 안에서 애니메이션 추가하기
- 우선 helper 함수인
keyframes
를 import 해주어야 한다.
import styled, { keyframes } from "styled-components";
const Wrapper = styled.div`
display: flex;
`;
const rotateAnimation = keyframes`
0% {
transform: rotate(0deg);
border-radius: 0px;
}
50% {
transform: rotate(180deg);
border-radius: 100px;
}
100% {
transform: rotate(360deg);
border-radius: 0px;
}
`;
const Box = styled.div`
height: 200px;
width: 200px;
background-color: tomato;
animation: ${rotateAnimation} 1s linear infinite;
`;
function App() {
return (
<Wrapper>
<Box />
</Wrapper>
);
}
export default App;
styled-components 가상 선택자
import styled from "styled-components";
const Wrapper = styled.div`
display: flex;
`;
const Box = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 200px;
width: 200px;
background-color: tomato;
span {
font-size: 36px;
&:hover {
font-size: 40px;
}
&:active {
opacity: 0;
}
}
`;
function App() {
return (
<Wrapper>
<Box>
<span>🙂</span>
</Box>
</Wrapper>
);
}
export default App;
import styled from "styled-components";
const Wrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
`;
const Emoji = styled.span``;
const EmojiTwo = styled.span``;
const Box = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 200px;
width: 200px;
background-color: tomato;
${Emoji} {
font-size: 36px;
&:hover {
font-size: 90px;
}
&:active {
opacity: 0;
}
}
${EmojiTwo}:hover {
font-size: 90px;
}
`;
function App() {
return (
<Wrapper>
<Box>
<Emoji>🙂</Emoji>
<EmojiTwo>🙁</EmojiTwo>
</Box>
</Wrapper>
);
}
export default App;
theme
- 모든 색상을 가지고 있는 Object
// index.js
import React from "react";
import ReactDOM from "react-dom/client";
import { ThemeProvider } from "styled-components";
import App from "./App";
const darkTheme = {
textColor: "whitesmoke",
backgroundColor: "#111",
};
const lightTheme = {
textColor: "#111",
backgroundColor: "whitesmoke",
};
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<ThemeProvider theme={darkTheme}>
<App />
</ThemeProvider>
</React.StrictMode>
);
// App.js
import styled, { keyframes } from "styled-components";
const Title = styled.h1`
color: ${(props) => props.theme.textColor};
`;
const Wrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background-color: ${(props) => props.theme.backgroundColor};
`;
// ... (코드 생략) ...
function App() {
return (
<Wrapper>
<Title>Hello</Title>
<Box>
<Emoji>🙂</Emoji>
<EmojiTwo>🙁</EmojiTwo>
</Box>
</Wrapper>
);
}
export default App;
전역 스타일링
// GlobalStyle.jsx (예시)
import { createGlobalStyle } from "styled-components";
import reset from "styled-reset";
const GlobalStyle = createGlobalStyle`
${reset}
* {
box-sizing: border-box;
font-family: 'Do Hyeon', sans-serif;
text-decoration: none;
font-size: 0.625rem;
margin: 0px;
padding: 0px;
list-style: none;
}
body {
background-image: url('./images/background-2426328_1920.jpg');
background-size: 100%;
height: 100%;
overflow: hidden;
}
`;
export default GlobalStyle;
// index.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import { ThemeProvider } from "styled-components";
import { RouterProvider } from "react-router-dom";
import router from "./Router";
import reportWebVitals from "./reportWebVitals";
import GlobalStyle from "./styles/GlobalStyle";
import GlobalFont from "./styles/GlobalFont";
import theme from "./styles/theme";
import variables from "./styles/variables";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<ThemeProvider theme={{ theme, variables }}>
<GlobalStyle />
<GlobalFont />
<RouterProvider router={router} />
</ThemeProvider>
);
reportWebVitals();
반응형
'◼ FrontEnd > Web & HTML, CSS' 카테고리의 다른 글
[Web] PWA(프로그래시브 웹 앱)이란 무엇일까? (2) | 2023.05.12 |
---|---|
[Web] CSR과 SSR이란 무엇일까? (0) | 2023.05.03 |
[NodeJS] Node JS & NPM 소개 및 설치 (0) | 2023.01.22 |
CSS 레이아웃 - Position과 Block 정리 (0) | 2022.10.23 |
Semantic Tag (시멘틱 태그) 를 사용하여 웹 개발을 해야하는 이유 (0) | 2022.10.23 |