CSS-in-JS는 JS 파일 내에서 CSS를 작성할 수 있는 방법.
CSS-in-JS는 js 파일 내에서 css 코드를 작성하기 때문에 css의 변수와 함수를 그대로 사용 가능. 그리고 css 클래스명을 해시 값으로 자동 생성하여 주기 때문에 클래스 이름 작명에 대한 수고가 감소함. 또한 컴포넌트와 스타일을 하나의 파일에서 관리하는 CSS-in-Js는 모듈화가 수월함.
CSS-in-JS는 여러 라이브러리가 있고 그 중 가장 인기있는 것이 styled-component.
프로젝트 시작 폴더에서
npm install styled-components
// App.js
import React from 'react';
import styled from 'styled-components'; // 1
const App = () => {
return <Title>styled-components!!</Title>; // 2
};
const Title = styled.h1` ⌉
font-size: 32px; |
text-align: center; | // 3
color: purple; |
`; ⌋
export default App;
<LogoImage src="/images/logo.png" alt="로고"/>
const [컴포넌트명] = styled.[html태그]`
[부여하고자 하는 css속성]
`;
// App.js
import React, { useState } from 'react';
import styled, { css } from 'styled-components';
const App = () => {
const [changeColor, setChangeColor] = useState(false);
const handleChanageColor = () => {
setChangeColor(!changeColor);
};
return (
<>
<Button onClick={handleChanageColor} primary={changeColor}> // props 전달
Button
</Button>
</>
);
}
const Button = styled.button`
padding: 20px;
margin: 10px;
border: none;
background-color: ${(props) => (props.primary ? "purple" : "pink")}; // 1
`; // props 동적으로 사용
export default App;
const [새로운 컴포넌트명] = styled(기존컴포넌트명)`
[부여하고자 하는 css 속성]
`;
예시)
// App.js
const App = () => {
return (
<>
<Button>Button</Button>
<NewButton>New Button</NewButton>
</>
);
};
const Button = styled.button`
margin: 20px;
padding: 20px;
border: none;
background-color: yellow;
font-size: 20px;
`;
const NewButton = styled(Button)`
color: white;
background-color: purple;
`; // color와 background-color외에는
// 기존 Button과 같은 속성을 공유함
export default App;
개발자 도구 확인
// Elements
<button class="sc-bczRLJ jgCBVB">Button</button> // 1
<button class="sc-bczRLJ sc-gsnTZi jgCBVB hXQPTY">New Button</button> // 2
<Button>
컴포의 class가 jsCBVB<NewButton>
컴포의 class는 jgCBVB hXQPTY로 <BUTTON>
컴포넌트의 스타일이 적용 됨.LINK, 아이콘 라이브러리 등 외부 라이브러리 컴포넌트도 import하면 아래처럼 사용 가능
// App.js
import { Link } from 'react-router-dom';
;import styled from 'styled-components';
const App = () => {
return <CartLink to="/cart">장바구니</CartLink>;
};
const CartLink = styled(Link)`
color: red;
`;
export default App;
// Elements
<a class="sc-eCYdqJ gubPie" href="/cart">장바구니</a>
스타일드 컴포넌트도 아래와 같이 네스팅 가능.
하지만 스타일 컴포넌트는 컴포넌트를 분리, 모듈화하기에 최적화되어있기 때문에 하나의 컴포넌트로 분리해서 사용하는 것이 좋다.
import React from 'react';
import styled from 'styled-components';
const Main = () => {
return (
<List>
<li>
메뉴<a href="http://list">클릭</a>
</li>
</List>
);
};
const List = styled.ul`
padding: 0;
li {
padding: 10px 0;
color: red;
font-size: 30px;
a {
color: green;
}
}
`;
export default Main;
네스팅이 필요한 경우도 있음.
react-slick과 같은 외부 라이브러리를 사용하여 이미 정해진 스타일을 변경해야한다면 네스팅을 이용하여 스타일링을 변경해야 함.
import React from 'react';
import styled from 'styled-components';
import Slider from 'react-slick';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
const Main = () => {
return (
<Carousel>
// slick 코드
</Carousel>
);
};
const Carousel = styled(Slider)`
.slick-slide {
// slick 커스텀 스타일
}
`;
export default Main;
스타일드 컴포넌트에서는 createGlobalStyle 함수를 통해 전역에 적용하기 위한 스타일 컴포넌트 생성 가능.
// src/styles/GlobalStyle.js
import React from 'react'
import { createGlobalStyle } from 'styled-components'
const GlobalStyle = createGlobalStyle`
* {
box-sizing: border-box;
font-family: 'Noto Sans KR', sans-serif;
}
`
export default GlobalStyle;
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import Router from './Router';
import GlobalStyle from './styles/GlobalStyle';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<ThemeProvider>
<GlobalStyle />
<Router />
</ThemeProvider>
);
reset도 가능.
npm install styled-reset
// src/styles/GlobalStyle.js
import React from 'react';
import { createGlobalStyle } from 'styled-components';
import reset from 'styled-reset';
const GlobalStyle = createGlobalStyle`
${reset}
* {
box-sizing: border-box;
font-family: 'Do Hyeon', sans-serif;
}
`;
export default GlobalStyle;
스타일드 컴포넌트에서는 ThemeProvider를 통하여 전역으로 테마, JS변수 등을 공유하여 사용함.
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import GlobalStyle from './styles/GlobalStyle';
import theme from './styles/theme';
import Router from './Router';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<ThemeProvider theme={theme}>
<GlobalStyle />
<Router />
</ThemeProvider>
);
color, fontSize 등 공통 테마는 theme.js에서 선언 후 각 컴포에서 props로 받아 스타일 적용이 가능함.
ThemeProvider의 속성으로 넘기면 전역에서 사용 가능
// theme.js
const theme = {
black: '#000000',
white: '#FFFFFF',
lightGrey: '#B0B0B0',
middleGrey: '#717171',
deepGrey: '#222222',
hoverGrey: '#DBDBDB',
};
export default theme;
// App.js
import { Link } from 'react-router-dom';
import styled from 'styled-components';
const App = () => {
return <Container>title</Container>;
};
const Container = styled.div`
background-color: ${props => props.theme.lightGrey}
`;
전역 props 콘솔 찍어보면.
// App.js
const Container = styled.div`
background-color: ${props => console.log(props)}
`;
// console.log(props)의 결과
props: {
children: 'title',
theme: {
black: '#000000',
white: '#FFFFFF',
lightGrey: '#B0B0B0',
middleGrey: '#717171',
deepGrey: '#222222',
hoverGrey: '#DBDBDB',
},
},
자주 사용하는 css 스타일은 variable.js파일 별도 관리
variable.js 는 theme과 varialbles를 Theme Provider에 같이 prop으로 합쳐서 전역에 사용하거나 사용하고자 하는 파일에서면 import해서 mixin을 사용할 수 있음.
// variables.js
import { css } from 'styled-components';
const variables = {
flex: (direction = 'row', justify = 'center', align = 'center') =>`
display: flex;
flex-direction: ${direction};
justify-content: ${justify};
align-items: ${align};
`,
absoluteCenter: css`
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
`,
};
export default variables;
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import GlobalStyle from './styles/GlobalStyle';
import theme from './styles/theme';
import variables from './styles/variables'
import Router from './Router';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<ThemeProvider theme={{ style: theme, variables }}>
<GlobalStyle />
<Router />
</ThemeProvider>
);
사용예시)
// App.js
const App = () => {
return (
<Container>
<Button>첫번째 버튼</Button>
<Button>두번째 버튼</Button>
</Container>
);
};
const Container = styled.div`
${(props) => props.theme.variables.flexSet()}
`; // a
const Button = styled.button`
background-color: ${(props) => props.theme.style.lightGrey};
`;
export default App;
기본 설정값 사용 ? -> flexSet()
바꾸고 싶엉 -> flexSet("","space-between","center")
// App.js
import styled from 'styled-components';
import variables from './styles/variables';
const App = () => {
return (
<Wrapper>
<Button primary="pink">Pink Button</Button>
<Button primary="Yellow">Yellow Button</Button>
</Wrapper>
);
};
const Wrapper = styled.div`
${variables.flex()}
`;
const Button = styled.button`
margin: 20px;
padding: 20px;
border: none;
background-color: ${(props) => props.primary};
font-size: 20px;
`;
export default App;
웹폰트는 임베드 코드 복사해서 html 파일에 코드 추가
// index.html
<head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Do+Hyeon&display=swap"
rel="stylesheet"
/>
</head>
src
└── styles
├── fonts
│ └── DoHyeon-Regular.ttf
├── GlobalFont.js
├── GlobalStyle.js
└── theme.js
// src/styles/GlobalFont.js
import { createGlobalStyle } from 'styled-components';
import DoHyeon from './fonts/DoHyeon-Regular.ttf';
const GlobalFont = createGlobalStyle`
@font-face {
font-family: 'Do Hyeon';
src: url(${DoHyeon}) format('woff');
}
`;
export default GlobalFont;
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import GlobalStyle from './styles/GlobalStyle';
import GlobalFont from './styles/GlobalFont';
import color from './styles/theme';
import Router from './Router';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<ThemeProvider theme={theme}>
<GlobalStyle />
<GlobalFont />
<Router />
</ThemeProvider>
);