-
Zero Runtime CSS-in-JS์ ๋ํด ์์๋ณด์TECH 2024. 1. 6. 23:02
์ต๊ทผ์ ์งํํ ํ๋ก์ ํธ์์ ์์ฆ์ ์ฃผ๋ชฉ๋ฐ๊ณ ์๋ Zero Runtime CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ, Vanilla Extract๋ฅผ ์ฌ์ฉํด ๋ณด์์ต๋๋ค. Vanilla Extract๋ ์ปดํ์ผ ํ์์ CSS ํ์ผ์ ์์ฑํ์ฌ ๊ธฐ์กด ๋ฐํ์์ ์์ฑ๋๋ CSS-in-JS๋ณด๋ค ์ฑ๋ฅ์์ ์ด์ ์ ์ ๊ณตํ๋ ๊ฒ์ผ๋ก ์๋ ค์ ธ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ๊ธฐ์กด์ CSS-in-JS์๋ ์ด๋ค ์ฑ๋ฅ์ ์ธ ๋ฌธ์ ๊ฐ ์์๊ธฐ ๋๋ฌธ์ Zero Runtime CSS-in-JS ๊ธฐ์ ์ด ๋ ์ค๋ฅด๊ฒ ๋์์๊น์?
์ด ํฌ์คํ ์์๋ ๋ฐํ์ CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํน์ง๊ณผ ๋ฌธ์ ๋ ๋ฌด์์ธ์ง, ๊ทธ๋ฆฌ๊ณ Zero Runtime ์ ๊ทผ ๋ฐฉ์์ด ๊ทธ ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ๋์ง์ ๋ํด ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
CSS ์ ์ฉ ๊ณผ์
CSS๊ฐ ์น ํ์ด์ง์ ์ ์ฉ๋๋ ๊ณผ์ ๋ถํฐ ์์๋ด ์๋ค.
- ๋คํธ์ํฌ์์ HTML์ ๋ฐ์ ๋ธ๋ผ์ฐ์ ๋ก ๋ก๋ฉํ๋ค.
- HTML์ DOM(Document Object Model)๋ก ๋ณํํ๋ค.
- ๋ธ๋ผ์ฐ์ ๋ HTML ๋ฌธ์์ ๋ฆฌ์์ค๋ค์ ๊ฐ์ ธ์จ๋ค. ์ด๋ฏธ์ง, ๋์์, CSS ๋ฑ์ด ํด๋น๋๋ค.
- ๋ธ๋ผ์ฐ์ ๋ ๊ฐ์ ธ์จ CSS๋ฅผ ๋ณํํ์ฌ CSSOM(CSS Object Model)์ ์์ฑํ๋ค. 2์์ ๋ง๋ค์ด์ง DOM Tree์ CSSOM Tree๋ฅผ ๊ฒฐํฉํ์ฌ ์คํ์ผ์ DOM ๋ ธ๋์ ์ ์ฉํ๋ค. ์ด๋, CSS Cascading ๊ท์น์ ๋ฐ๋ผ ์คํ์ผ์ด ์ ์ฉ๋๋ค. ์ด ๊ณผ์ ์ Render Tree๋ผ๊ณ ํ๋ค.
- ํ์ด์ง๋ฅผ ํ๋ฉด์ ๊ทธ๋ฆฐ๋ค. ์ด ๋จ๊ณ๋ฅผ Painting์ด๋ผ๊ณ ํ๋ค.
์ ๊ณผ์ ์ ๊ทธ๋ฆผ์ผ๋ก ํํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
CSS์ ๋ ๋๋ง ๋ฌธ์
์์์ ์ค๋ช ํ ๊ฒ์ฒ๋ผ ๋ธ๋ผ์ฐ์ ๋ HTML์ ๋จผ์ ๋ฐ์์จ ๋ค์ CSSOM์ ์์ฑํ์ฌ HTML์ ์คํ์ผ์ ์ ์ฉ์ํฌ ์ค๋น๋ฅผ ํฉ๋๋ค.
์ฌ๊ธฐ์ CSS๋ก ์ธํด ๋ฐ์ํ๋ ๋ ๋๋ง ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
ํ ํ์ด์ง์ ์ ์ฉ๋ CSS์ ์๋ง์ ์คํ์ผ๊ณผ ์ ํ์๊ฐ ํฌํจ๋์ด ์๋ค๋ฉด ์ด๋จ๊น์? CSS ํ์ผ์ ํฌ๊ธฐ๊ฐ ํด์๋ก ๋ธ๋ผ์ฐ์ ๊ฐ CSSOM์ ๋ง๋๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ด ๊ธธ์ด์ง๋๋ค.
์ด ๊ณผ์ ์์ ๋ ๋๋ง ๋ธ๋กํน์ด ๋ฐ์ํด ์์ฒญ๋ ํ์ด์ง์ ์ฒซ Painting์ด ์ง์ฐ๋ ์ ์์ต๋๋ค.
์ฒซ Painting์ ๋ธ๋ผ์ฐ์ ๊ฐ ์์ฒญ๋ ํ์ด์ง์ ์ฒซ ๋ฒ์งธ ํฝ์ ์ ๋ ๋๋งํ๋ ์ด๋ฒคํธ์ ๋๋ค.
์ฒซ Painting์ด 0.5์ด ์ด์ ์ง์ฐ๋๋ค๋ฉด ์ฌ์ฉ์ ๊ฒฝํ์ด ์ ํ๋์ด ๋ถ์ ์ ์ธ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค.
ํด๋ผ์ด์ธํธ์๊ฒ CSS๋ฅผ ๋ ๋นจ๋ฆฌ ์ ๋ฌํ๊ณ ์ฒซ Painting ์๊ฐ์ ์ต์ ํํ์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํด์ผ ํฉ๋๋ค.โ๏ธ CSS-in-JS: ๋ ๋๋ง ๋ธ๋กํน ํด๊ฒฐ๊ณผ ํด๋์ค ์ค๋ณต ๋ฐฉ์ง
๋ ๋๋ง ๋ธ๋กํน์ ํด๊ฒฐํ๋ ค๋ฉด CSS ํ์ผ์ ์ปดํฌ๋ํธํํ์ฌ chunk(์์ ๋ฉ์ด๋ฆฌ)๋ก ๋ถํ ํ๋ฉด ๋ฉ๋๋ค.
๊ทธ๋ฌ๋ ์ด ๋ฐฉ๋ฒ์ ๋์ผํ ํด๋์ค ์ด๋ฆ์ ์ฌ์ฉํ ๊ฒฝ์ฐ ์ ์ญ์ ์ผ๋ก ์คํ์ผ์ด ์ค๋ณต๋์ด ๋์์ธ ์์ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
CSS-in-JS๊ฐ ์ด๋ฌํ ํด๋์ค ์ค๋ณต๊ณผ ๋ฒ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด ์ค๋๋ค.
CSS-in-JS์ ์ฅ์
CSS-in-JS๊ฐ ํด๊ฒฐํ๋ ๊ฐ์ฅ ํฐ ๋ฌธ์ ๋ ์์์ ์งง๊ฒ ์ค๋ช ํ ๊ธ๋ก๋ฒ ์ค์ฝํ ๋ฌธ์ ์ธ๋ฐ,
์ด์ธ์๋ CSS-in-JS๊ฐ ๊ฐ์ง๊ณ ์๋ ์ฅ์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1๏ธโฃ CSS ํ์ผ์ JavaScript์ ํจ๊ป ๊ด๋ฆฌ
๋์ผํ ํ์ผ์ JavaScript ์ฝ๋์ ์คํ์ผ ์ฝ๋๋ฅผ ํจ๊ป ์์ฑํด ์ปดํฌ๋ํธ์ ์ ์ง๋ณด์๊ฐ ๋ณด๋ค ๋ ์ฉ์ดํฉ๋๋ค.
2๏ธโฃ ์ค์ฝํ ๋ฐ ์ ํ์ ๊ด๋ จ
CSS-in-JS๋ JavaScript ํ์ผ๋ง๋ค ์คํ์ผ์ ์์ฑํ๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ์ปดํฌ๋ํธ์ ์คํ์ผ๊ณผ ์ถฉ๋ํ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค.
์คํ์ผ ์ถฉ๋์ ํผํ๊ธฐ ์ํด ์ด๋ค CSS ๋ฐฉ๋ฒ๋ก ์ ์ฌ์ฉํ ์ง ๊ฑฑ์ ํ ํ์๋ ์์ต๋๋ค.
๋ณดํต ์คํ์ผ์ ์์ฑํ ๋ ์ ํ์๋ฅผ ์์ ๋ถ์ด์ง ์๊ณ ํ๋์ ์ปดํฌ๋ํธ์ ๋ํด์๋ง ์์ฑํ๋ฏ๋ก, specificity ๋ฌธ์ ๋ ๊ฑฐ์ ๋ฐ์ํ์ง ์์ต๋๋ค.
3๏ธโฃ ๋์ ์คํ์ผ๋ง
CSS-in-JS๋ ๋ค์๊ณผ ๊ฐ์ด ์กฐ๊ฑด๋ถ CSS๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
import styled from 'styled-components'; const Title = styled.h1<{ highlight?: boolean }>` font-size: 1.5em; text-align: center; color: ${(props) => (props.highlight ? 'black' : '#BF4F74')}; `; function App() { return ( <> <Title>Hello World</Title> <Title highlight>Hello World</Title> </> ); } export default App;
CSS-in-JS์ ๋จ์
CSS-in-JS๊ฐ ์ปดํฌ๋ํธ ๋จ์๋ก CSS๋ฅผ ๋๋์ด ์์ฑํ ์๋ ์์ง๋ง, ์์์ ์ค๋ช ํ๋ ๋ ๋๋ง ๋ธ๋กํน์ ์์ ํ ํด๊ฒฐํ์ง๋ ๋ชปํฉ๋๋ค.
์ด์ธ์๋ ๋ช ๊ฐ์ง ๋จ์ ์ด ์์ต๋๋ค.
1๏ธโฃ ๋ ๋๋ง ๋ธ๋กํน
CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ *์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง๋ ๋ ์๋ก์ด ์คํ์ผ์ ๋์ ์ผ๋ก ๊ณ์ฐํด ์ถ๊ฐํ๋ ๋ฐฉ์์ผ๋ก ๋์ํ๋ฉฐ, ์ด๋ ๊ทผ๋ณธ์ ์ผ๋ก ์ฑ๋ฅ์ ์ข์ง ์์ต๋๋ค.
์ปดํฌ๋ํธ๊ฐ ๋ง์์๋ก ์ฒซ Painting ์๊ฐ์ด ๊ธธ์ด์ ธ ๋ ๋๋ง ๋ธ๋กํน์ด ์๊ธฐ๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ํดํฉ๋๋ค.*์์
import { useState } from 'react'; import styled from 'styled-components'; const Title = styled.h1<{ $primary?: boolean }>` font-size: 1.5em; text-align: center; color: ${(props) => (props.$primary ? '#000000' : '#BF4F74')}; `; function App() { const [primary, setPrimary] = useState(false); const changeColorStyledComponent = () => { setPrimary((p) => !p); }; return ( <> <Title $primary={primary}>Hello World</Title> <button onClick={changeColorStyledComponent}>change color</button> </> ); } export default App;
์ฌ์ฉ์๊ฐ ๋ฒํผ์ ๋๋ ์ ๋ ๋์ ์ผ๋ก ์คํ์ผ์ด ์ถ๊ฐ๋๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.
2๏ธโฃ SSR๊ณผ์ ํธํ์ฑ
CSS-in-JS๋ ๋ฐํ์์ ์คํ์ผ์ ์์ฑํ๊ณ , ์๋ฒ์์ ํ์ด์ง์ ์ด๊ธฐ HTML์ ์์ฑํ๋ SSR ๋ฐฉ์์ ์๋ก ์์ถฉ๋๋ ์๊ตฌ์ฌํญ์ผ๋ก ์ธํด ์๊ธฐ๋ ๋ฌธ์ ๊ฐ ๋ง์ต๋๋ค.
์๋ฒ์์ ์์ฑ๋ HTML์ด ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ๋ก ์ ๋ฌ๋๊ธฐ ์ ๊น์ง CSS-in-JS๋ก ์์ฑํ ์คํ์ผ์ด ์ ์ฉ๋์ง ์์ต๋๋ค.
์ด๋ ์ด๊ธฐ ๋ก๋ฉ ์ ์คํ์ผ์ด ์ ์ฉ๋์ง ์์ ์ฝํ ์ธ ๊ฐ ๊น๋นก์ด๋ฉฐ ๋ณด์ด๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
Next.js์ ๊ณต์ ๋ฌธ์์๋ ๋ฐํ์ ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ํ์ํ CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ์ฌ ์๋ฒ ์ปดํฌ๋ํธ์์ ์ง์๋์ง ์๋๋ค๋ ์ฃผ์ ๋ฌธ๊ตฌ๊ฐ ์จ ์๊ณ ,
Emotion GitHub ๋ฆฌํฌ์งํ ๋ฆฌ์๋ ์ด์ ๊ด๋ จ๋ ์๋ง์ ๋ฌธ์ ๊ฐ ์ ์๋ฉ๋๋ค.
Zero Runtime CSS-in-JS
์ด๋ฌํ CSS-in-JS์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด, Zero Runtime CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ง๋ค์ด์ง๊ฒ ๋ฉ๋๋ค.
Zero Runtime ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์๋ CSS-in-JS ์ฝ๋๋ฅผ CSS ํ์ผ๋ก ๋จผ์ ๋ณํํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ธ๋ผ์ฐ์ ๊ฐ ํด๋น ์คํ์ผ์ ์ฝ๊ณ ์น ํ์ด์ง์ ์ ์ฉํฉ๋๋ค.
์ด ๋ฐฉ์์ผ๋ก ๋ฐํ์์ ์คํ์ผ ํ๊ทธ๋ฅผ ์์ฑํจ์ผ๋ก์จ ๋ฐ์ํ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
์์์ ๋ณด์ฌ ๋๋ฆฐ ์ฌ์ฉ์๊ฐ ๋ฒํผ์ ๋๋ ์ ๋ ํ ์คํธ์ ์์์ด ๋ณ๊ฒฝ๋๋ ๋์ผํ ๊ธฐ๋ฅ์ Vanilla Extract๋ก ์์ฑํ ์์ ์ ๋๋ค.
import { useState } from 'react'; import { title } from './test.css'; function App() { const [primary, setPrimary] = useState(false); const changeColor = () => { setPrimary((p) => !p); }; return ( <> <h1 className={`${title} ${primary ? 'primary' : ''}`}>Hello World</h1> <button onClick={changeColor}>change color</button> </> ); } export default App;
// test.css.ts import { style } from '@vanilla-extract/css'; export const title = style({ fontSize: '1.5em', textAlign: 'center', color: '#BF4F74', selectors: { [`&.primary`]: { color: 'black', }, }, });
๋น๋ ํ์์ ๋ฒํผ์ ๋๋ ์ ๋์ ์คํ์ผ๊น์ง ๋ชจ๋ ๊ณ์ฐ๋์ด HTML๊ณผ CSS์ ์ด๊ธฐ ๋ก๋ฉ์ด ์๋ฃ๋๋ฉด style ํ๊ทธ์์ ํ์ธํ ์ ์์ต๋๋ค.
Vanilla Extract ์ธ์๋ Linaria, Astroturf, Reshadow, Panda CSS ๋ฑ ๋ค์ํ Zero Runtime CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์ต๋๋ค.
Vanilla Extract
Vanilla Extract๋ GitHub์์ 2024๋ 1์ ๊ธฐ์ค 9์ฒ ๊ฐ ์ด์์ ์คํ๋ฅผ ๋ฐ์ ์ธ๊ธฐ ์๋ Zero Runtime CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
ํ๋ ์์ํฌ์ ๊ตฌ์ ๋ฐ์ง ์์ ๋ฐ๋๋ผ ์๋ฐ์คํฌ๋ฆฝํธ ๋๋ ๋ชจ๋ ํ๋ก ํธ์๋ ํ๋ ์์ํฌ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Vanilla Extract๋ฅผ ์ฌ์ฉํ๋ฉด ๋ก์ปฌ ๋ฒ์์ ์คํ์ผ๊ณผ ๋ณ์๋ฅผ JavaScript ๋๋ TypeScript๋ก ์์ฑํ๊ณ ๋น๋ ์์ ์ CSS ํ์ผ์ ์์ฑํ ์ ์์ต๋๋ค. ๋ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ๋ง๋ฅผ ๋์ ์ผ๋ก ์ง์ ํ๊ธฐ ์ํ API๋ ์ ๊ณตํฉ๋๋ค.
Vanilla Extract์ ๋ค๋ฅธ ํน์ง์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ํ์ ์์ : ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ง์ํ์ฌ ๊ฐ๋ฐ์ ๊ฒฝํ์ ๊ฐ์ ํฉ๋๋ค.
- ๋ฒ๋ค๋ฌ ์ง์: ์นํฉ, Vite, Parcel, Babel๊ณผ ๊ฐ์ ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ํ๋ก ํธ์๋ React ํ๋ ์์ํฌ ๋ฐ ๋๊ตฌ์ ํตํฉ๋์ด ์์ต๋๋ค.
- ์ ๋ฌธ์ํ๋จ
- ์ฌ์ด ์ค์
- ์ฌ๋ฌ ํจํค์ง์ ํจ๊ป ์ฌ์ฉํ ์ ์์ (sprinkles, recipe, dynamic)
- sprinkles๋ฅผ ํ์ฉํด tailwind์ฒ๋ผ Atomic CSS๋ฅผ ๊ตฌ์ฑํ ์ ์์
- recipe๋ฅผ ํ์ฉํ์ฌ variant ๊ธฐ๋ฐ ์คํ์ผ๋ง์ ๊ตฌ์ฑํ ์ ์์
- dynamic์ ํ์ฉํด ๋์ ์ผ๋ก ๊ฐ์ ์ ๋ฐ์ดํธํ ์ ์์
๊ธ์ ๋ง์น๋ฉฐ
์ด ํฌ์คํ ์์, Vanilla Extract์ ๊ฐ์ Zero Runtime CSS-in-JS ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ธฐ์กด CSS-in-JS ๋ฐฉ์์ ํ๊ณ๋ฅผ ์ด๋ป๊ฒ ๊ทน๋ณตํ๋์ง ์์๋ณด์์ต๋๋ค. Zero Runtime CSS-in-JS๋ ์ปดํ์ผ ํ์์ CSS ํ์ผ์ ์์ฑํจ์ผ๋ก์จ ๋ฐํ์ ๋ ๋๋ง ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ , ์ฑ๋ฅ์ ํฅ์์ํต๋๋ค. ์ด๋ฅผ ํตํด ์น ์๋น์ค์์ ์ค์ํ ์ฒซ ํ๋ฉด ๋ก๋ฉ ์๊ฐ์ ๋จ์ถํ์ฌ ์ข์ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ง๋ค ์ ์์ต๋๋ค.
๐ ์ฐธ๊ณ
'TECH' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
useState, ํด๋ก์ ๋ฅผ ํ์ฉํ์ฌ ๋์ํ๋ค๊ณ ? (0) 2024.01.27 React์์ Event Handler๋ ์ด๋ป๊ฒ ๋์ํ ๊น์? (0) 2024.01.11 React์์ TMap API ์ฌ์ฉํ๊ธฐ (1) 2023.12.30 ์ ์ ์์ ์ ์ src์์ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ข์๊น? (2) 2023.12.16 CSS์ ์ฐ์ ์์, CSS Cascading (0) 2023.09.04