[Daily morning study] CSS-in-JS vs CSS Modules ๋น๊ต
#daily morning study
CSS ์คํ์ผ๋ง ๋ฐฉ์์ ๋ฐฐ๊ฒฝ
์ ํต์ ์ธ CSS๋ ์ ์ญ ์ค์ฝํ๋ก ๋์ํ๋ค. ํด๋์ค ์ด๋ฆ์ด ํ๋ก์ ํธ ์ด๋์๋ ์ถฉ๋ํ ์ ์๊ณ , ์ด๋ค ์ปดํฌ๋ํธ๊ฐ ์ด๋ค ์คํ์ผ์ ์ฐ๋์ง ์ถ์ ํ๊ธฐ ์ด๋ ต๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด CSS Modules์ CSS-in-JS ๋ ๊ฐ์ง ์ ๊ทผ๋ฒ์ด ๋ฑ์ฅํ๋ค.
CSS Modules
๊ฐ๋
CSS ํ์ผ์ ๋ชจ๋์ฒ๋ผ importํด์ ํด๋์ค ์ด๋ฆ์ ๋ก์ปฌ ์ค์ฝํ๋ก ๋ง๋๋ ๋ฐฉ์์ด๋ค. Webpack, Vite ๋ฑ ์ฃผ์ ๋น๋ ๋๊ตฌ์์ ๊ธฐ๋ณธ ์ง์ํ๋ฉฐ, ๋ณ๋ ๋ฐํ์์ด ํ์ ์๋ค.
๋์ ๋ฐฉ์
๋น๋ ํ์์ ๊ฐ ํด๋์ค๋ช ์ ๊ณ ์ ํ ํด์๊ฐ ํฌํจ๋ ์ด๋ฆ์ผ๋ก ๋ณํํ๋ค.
/* Button.module.css */
.button {
background-color: blue;
color: white;
padding: 8px 16px;
}
// Button.jsx
import styles from './Button.module.css';
function Button({ children }) {
return <button className={styles.button}>{children}</button>;
}
๋น๋ ํ ์ค์ HTML์๋ .Button_button__abc12 ๊ฐ์ ๊ณ ์ ํด๋์ค๋ช
์ด ์ฝ์
๋๋ค. ์ถฉ๋์ด ๊ตฌ์กฐ์ ์ผ๋ก ๋ถ๊ฐ๋ฅํ๋ค.
์ฅ์
- ๋น๋ ํ์ ์ฒ๋ฆฌ โ ๋ฐํ์ ์ค๋ฒํค๋ ์์
- ๊ธฐ์กด CSS ๋ฌธ๋ฒ ๊ทธ๋๋ก ์ฌ์ฉ ๊ฐ๋ฅ
- Sass, Less ๋ฑ ์ ์ฒ๋ฆฌ๊ธฐ์ ์กฐํฉ ๊ฐ๋ฅ
- React Server Components(RSC)์ ์์ ํธํ
๋จ์
- ๋์ ์คํ์ผ๋ง์ด ๋ฒ๊ฑฐ๋กญ๋ค. props์ ๋ฐ๋ผ ์คํ์ผ์ ๋ฐ๊พธ๋ ค๋ฉด className์ ์กฐ๊ฑด๋ถ๋ก ์กฐํฉํด์ผ ํ๋ค.
- ์คํ์ผ ํ์ผ๊ณผ ์ปดํฌ๋ํธ ํ์ผ์ด ๋ถ๋ฆฌ๋์ด ์์ด ํ์ผ ์๊ฐ ๋์ด๋๋ค.
// ๋์ ์คํ์ผ๋ง โ ๋ถํธํ์ง๋ง ๊ฐ๋ฅ
import styles from './Button.module.css';
import cx from 'classnames';
function Button({ primary, children }) {
return (
<button className={cx(styles.button, { [styles.primary]: primary })}>
{children}
</button>
);
}
CSS-in-JS
๊ฐ๋
์คํ์ผ์ JS/TSX ํ์ผ ๋ด๋ถ์์ ์ง์ ์ ์ธํ๋ ๋ฐฉ์์ด๋ค. ๋ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก styled-components, Emotion์ด ์๋ค.
๋์ ๋ฐฉ์
์ปดํฌ๋ํธ ๋จ์๋ก ์คํ์ผ์ ์ ์ธํ๊ณ , ๋ฐํ์์ ๋์ ์ผ๋ก CSS ํด๋์ค๋ฅผ ์์ฑํด์ <style> ํ๊ทธ์ ์ฃผ์
ํ๋ค.
// styled-components ์์
import styled from 'styled-components';
const Button = styled.button`
background-color: ${(props) => (props.$primary ? 'blue' : 'white')};
color: ${(props) => (props.$primary ? 'white' : 'black')};
padding: 8px 16px;
`;
function App() {
return <Button $primary>Click me</Button>;
}
Emotion์ css prop ๋ฐฉ์๋ ์ ๊ณตํ๋ค.
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
const buttonStyle = (primary) => css`
background-color: ${primary ? 'blue' : 'white'};
color: ${primary ? 'white' : 'black'};
padding: 8px 16px;
`;
function Button({ primary, children }) {
return <button css={buttonStyle(primary)}>{children}</button>;
}
์ฅ์
- JS ๋ณ์, props, ์ํ ๊ฐ์ ์คํ์ผ์ ์ง์ ํ์ฉ โ ๋์ ์คํ์ผ๋ง์ด ์์ฐ์ค๋ฝ๋ค
- ์คํ์ผ๊ณผ ์ปดํฌ๋ํธ ๋ก์ง์ด ํ ํ์ผ์ ์์ด ์์ง๋๊ฐ ๋๋ค
- ํด๋์ค๋ช ์ถฉ๋์ด ์๋์ผ๋ก ๋ฐฉ์ง๋๋ค
๋จ์
- ๋ฐํ์ ์ค๋ฒํค๋: ์คํ์ผ์ ๋ฐํ์์ ์์ฑยท์ฃผ์ ํ๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ ๋น์ฉ์ด ์๋ค
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฒด์ ๋ฒ๋ค ํฌ๊ธฐ ์ถ๊ฐ (styled-components ~30KB gzip ๊ธฐ์ค)
- React Server Components(RSC)์์ ๋์ํ์ง ์๋๋ค. ์๋ฒ ์ปดํฌ๋ํธ๋ ๋ฐํ์ JS๋ฅผ ์คํํ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
- SSR ํ๊ฒฝ์์ ๋ณ๋ ์ค์ ์ด ํ์ํ๋ค
๋น๊ต ์์ฝ
| ํญ๋ชฉ | CSS Modules | CSS-in-JS (styled-components, Emotion) |
|---|---|---|
| ์คํ์ผ ์์น | ๋ณ๋ .module.css ํ์ผ | JS/TSX ํ์ผ ๋ด๋ถ |
| ์ฒ๋ฆฌ ์์ | ๋น๋ ํ์ | ๋ฐํ์ |
| ๋์ ์คํ์ผ๋ง | ๋ถํธ (className ์กฐํฉ ํ์) | ์์ฐ์ค๋ฝ๊ณ ๊ฐ๊ฒฐํจ |
| ๋ฐํ์ ์ฑ๋ฅ | ์ฐ์ (์ค๋ฒํค๋ ์์) | ์๋์ ์ผ๋ก ๋๋ฆผ |
| RSC ํธํ์ฑ | ๊ฐ๋ฅ | ๋๋ถ๋ถ ๋ถ๊ฐ |
| ๋ฒ๋ค ํฌ๊ธฐ | ์ํฅ ์์ | ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋งํผ ์ฆ๊ฐ |
| CSS ์ ์ฒ๋ฆฌ๊ธฐ ์ง์ | ๊ฐ๋ฅ | ๋ณ๋ ์ค์ ํ์ |
Zero-runtime CSS-in-JS
๋ฐํ์ ๋น์ฉ ์์ด CSS-in-JS์ ํธ์์ฑ์ ์ป์ผ๋ ค๋ ์๋๋ก Zero-runtime ๋ฐฉ์์ด ๋ฑ์ฅํ๋ค. ๋ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ: vanilla-extract, Panda CSS, Linaria
์ด ๋๊ตฌ๋ค์ JS์์ ์คํ์ผ์ ์์ฑํ์ง๋ง, ๋น๋ ํ์์ ์ ์ CSS ํ์ผ์ ์์ฑํ๋ค.
// vanilla-extract ์์
import { style } from '@vanilla-extract/css';
export const button = style({
backgroundColor: 'blue',
color: 'white',
padding: '8px 16px',
});
// ๋์ ์คํ์ผ์ styleVariants๋ก ์ฒ๋ฆฌ
import { styleVariants } from '@vanilla-extract/css';
export const buttonVariant = styleVariants({
primary: { backgroundColor: 'blue', color: 'white' },
secondary: { backgroundColor: 'white', color: 'black' },
});
๋น๋ ํ .css ํ์ผ์ด ์์ฑ๋๋ฉฐ, ๋ฐํ์์๋ ํด๋์ค๋ช
๋ง ์ฐธ์กฐํ๋ค. RSC์๋ ํธํ๋๊ณ ์ฑ๋ฅ์ CSS Modules ์์ค์ด๋ค.
์ ํ ๊ธฐ์ค
- ์ ์ ์คํ์ผ ์์ฃผ, ์ฑ๋ฅ ์ค์, Next.js App Router ์ฌ์ฉ โ CSS Modules ๋๋ vanilla-extract
- ๋์ ์คํ์ผ๋ง ๋น๋ฒ, ๊ฐ๋ฐ ํธ์์ฑ ์ฐ์ , Pages Router ๋๋ CRA โ Emotion, styled-components
- ํ์ ์์ ์ฑ๊ณผ Zero-runtime ๋ ๋ค ์ํจ โ vanilla-extract
Next.js 13+ App Router์์ ๋ฐํ์ CSS-in-JS๋ฅผ ์ฐ๋ฉด ์๋ฒ ์ปดํฌ๋ํธ์์๋ ์คํ์ผ์ด ์ ์ฉ๋์ง ์๊ณ , ๋ฌด์กฐ๊ฑด ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ('use client')๋ก ์ ์ธํด์ผ ํ๋ค. ์ด ์ ์ฝ ๋๋ฌธ์ ์ต๊ทผ ํ๋ก์ ํธ์์๋ CSS Modules๋ Tailwind CSS๋ก ์ ํํ๋ ์ฌ๋ก๊ฐ ๋๊ณ ์๋ค.