August 6, 2025

🧱 CSS-in-JS 과용: λŸ°νƒ€μž„ μ˜€λ²„ν—€λ“œμ™€ λ²ˆλ“€ 크기 증가, 그리고 CSS μ΅œμ ν™” λ‚œν•­

React
CSS
μ„±λŠ₯
μ•„ν‚€ν…μ²˜
μ»΄ν¬λ„ŒνŠΈ
λΉŒλ“œ&λ²ˆλ“€λ§
λ Œλ”λ§μ „λž΅

Summary

CSS-in-JSλŠ” μœ μš©ν•œ λ„κ΅¬μ΄μ§€λ§Œ, κ³Όλ„ν•˜κ²Œ μ‚¬μš©ν•˜λ©΄ λŸ°νƒ€μž„ μ˜€λ²„ν—€λ“œ, λ²ˆλ“€ 크기 증가, CSS μ΅œμ ν™” λ‚œν•­ λ“± λ‹€μ–‘ν•œ 문제λ₯Ό μ•ΌκΈ°ν•©λ‹ˆλ‹€. CSS Modules, Atomic CSS, 쑰건뢀 CSS-in-JS μ‚¬μš© λ“±μ˜ λŒ€μ•ˆμ„ κ³ λ €ν•˜μ—¬ ν”„λ‘œμ νŠΈ μš”κ΅¬μ‚¬ν•­μ— λ§žλŠ” 졜적의 μŠ€νƒ€μΌλ§ μ „λž΅μ„ 선택해야 ν•©λ‹ˆλ‹€.

Why Wrong?

CSS-in-JSλŠ” μ»΄ν¬λ„ŒνŠΈ μŠ€νƒ€μΌλ§μ— κ°•λ ₯ν•œ λ„κ΅¬μ΄μ§€λ§Œ, λͺ¨λ“  상황에 μ ν•©ν•œ 해결책은 μ•„λ‹™λ‹ˆλ‹€. κ³Όλ„ν•˜κ²Œ μ‚¬μš©ν•˜λ©΄ λ‹€μŒκ³Ό 같은 문제점이 λ°œμƒν•©λ‹ˆλ‹€.

  • λŸ°νƒ€μž„ μ˜€λ²„ν—€λ“œ: CSS-in-JSλŠ” λΈŒλΌμš°μ €κ°€ HTML을 νŒŒμ‹±ν•œ ν›„ JavaScriptλ₯Ό μ‹€ν–‰ν•˜μ—¬ μŠ€νƒ€μΌμ„ λ™μ μœΌλ‘œ μƒμ„±ν•˜κ³  μ£Όμž…ν•©λ‹ˆλ‹€. 이 과정은 κΈ°μ‘΄ CSS 파일 λ‘œλ”© 방식에 λΉ„ν•΄ 좔가적인 λŸ°νƒ€μž„ μ˜€λ²„ν—€λ“œλ₯Ό λ°œμƒμ‹œμΌœ 초기 λ Œλ”λ§ μ„±λŠ₯을 μ €ν•˜μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • λ²ˆλ“€ 크기 증가: CSS-in-JS λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 자체적으둜 μƒλ‹Ήν•œ 크기λ₯Ό κ°€μ§€λ©°, μ»΄ν¬λ„ŒνŠΈλ§ˆλ‹€ μŠ€νƒ€μΌμ„ μ •μ˜ν•  λ•Œλ§ˆλ‹€ λ²ˆλ“€ 크기가 μ¦κ°€ν•©λ‹ˆλ‹€. μ΄λŠ” 초기 λ‘œλ”© μ‹œκ°„ μ¦κ°€λ‘œ 이어져 μ‚¬μš©μž κ²½ν—˜μ„ μ €ν•΄ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • CSS μ΅œμ ν™” λ‚œν•­: CSS-in-JSλŠ” λŸ°νƒ€μž„μ— μŠ€νƒ€μΌμ΄ μƒμ„±λ˜λ―€λ‘œ, μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” CSS κ·œμΉ™μ„ μ œκ±°ν•˜λŠ” Dead Code Eliminationμ΄λ‚˜ CSS Minificationκ³Ό 같은 μ΅œμ ν™” 기법을 μ μš©ν•˜κΈ° μ–΄λ ΅μŠ΅λ‹ˆλ‹€. 이둜 인해 λΆˆν•„μš”ν•œ μŠ€νƒ€μΌμ΄ 계속 남아 λ²ˆλ“€ 크기λ₯Ό μ¦κ°€μ‹œν‚€κ³  μ„±λŠ₯을 μ €ν•˜μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • CSS 캐싱 문제: CSS-in-JS둜 μƒμ„±λœ μŠ€νƒ€μΌμ€ 보톡 JavaScript λ²ˆλ“€μ— ν¬ν•¨λ˜λ―€λ‘œ, CSS 파일처럼 λ³„λ„λ‘œ μΊμ‹±λ˜μ§€ μ•Šμ•„ νŽ˜μ΄μ§€ 이동 μ‹œλ§ˆλ‹€ μŠ€νƒ€μΌμ„ λ‹€μ‹œ 생성해야 ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” μ‚¬μš©μž κ²½ν—˜μ„ λ”μš± μ•…ν™”μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
  • SSR μ„±λŠ₯: μ„œλ²„ μ‚¬μ΄λ“œ λ Œλ”λ§(SSR) ν™˜κ²½μ—μ„œ CSS-in-JSλ₯Ό μ‚¬μš©ν•˜λ©΄ μŠ€νƒ€μΌμ„ μ„œλ²„μ—μ„œ 생성해야 ν•˜λ―€λ‘œ, μ„œλ²„ μžμ›μ„ μ†Œλͺ¨μ‹œν‚€κ³  TTFB(Time To First Byte)λ₯Ό μ¦κ°€μ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

How to Fix?

CSS-in-JSλ₯Ό μ‚¬μš©ν•  λ•ŒλŠ” λ‹€μŒκ³Ό 같은 사항을 κ³ λ €ν•˜μ—¬ μ‹ μ€‘ν•˜κ²Œ μ μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

  • CSS Modules: CSS ModulesλŠ” μ»΄ν¬λ„ŒνŠΈ μŠ€μ½”ν”„λ₯Ό μ§€μ›ν•˜λ©΄μ„œλ„ CSS 파일둜 κ΄€λ¦¬λ˜λ―€λ‘œ, CSS-in-JS의 μž₯점과 κΈ°μ‘΄ CSS의 μž₯점을 λͺ¨λ‘ ν™œμš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • Atomic CSS: Tailwind CSS와 같은 Atomic CSS ν”„λ ˆμž„μ›Œν¬λŠ” μž¬μ‚¬μš© κ°€λŠ₯ν•œ μŠ€νƒ€μΌ 클래슀λ₯Ό μ œκ³΅ν•˜μ—¬ CSS μž‘μ„±λŸ‰μ„ 쀄이고 μŠ€νƒ€μΌ 일관성을 μœ μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 쑰건뢀 CSS-in-JS: μ»΄ν¬λ„ŒνŠΈμ˜ μŠ€νƒ€μΌμ΄ λ™μ μœΌλ‘œ λ³€κ²½λ˜λŠ” κ²½μš°μ—λ§Œ CSS-in-JSλ₯Ό μ‚¬μš©ν•˜κ³ , 정적인 μŠ€νƒ€μΌμ€ CSS 파일둜 κ΄€λ¦¬ν•˜λŠ” 방식을 κ³ λ €ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μ μ ˆν•œ CSS-in-JS 라이브러리 선택: μ„±λŠ₯ μ΅œμ ν™”κ°€ 잘 된 CSS-in-JS 라이브러리λ₯Ό μ„ νƒν•˜κ³ , ν•„μš”ν•œ κΈ°λŠ₯만 μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. (예: Linaria, Astroturf λ“±)
  • CSS κ·œμΉ™ μž¬μ‚¬μš©: λ””μžμΈ μ‹œμŠ€ν…œμ„ κ΅¬μΆ•ν•˜μ—¬ μŠ€νƒ€μΌ κ·œμΉ™μ„ μž¬μ‚¬μš©ν•˜κ³ , ν…Œλ§ˆλ₯Ό ν™œμš©ν•˜μ—¬ μŠ€νƒ€μΌ 변경을 효율적으둜 관리해야 ν•©λ‹ˆλ‹€.

Before Code (Bad)

// κ³Όλ„ν•œ CSS-in-JS μ‚¬μš© μ˜ˆμ‹œ (styled-components)
import styled from 'styled-components';

const Button = styled.button`
  background-color: ${props => props.primary ? 'palevioletred' : 'white'};
  color: ${props => props.primary ? 'white' : 'palevioletred'};
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;

function MyComponent() {
  return (
    <div>
      <Button>Normal Button</Button>
      <Button primary>Primary Button</Button>
    </div>
  );
}

After Code (Good)

// CSS Modules μ‚¬μš© μ˜ˆμ‹œ
import styles from './MyComponent.module.css';

function MyComponent() {
  return (
    <div>
      <button className={styles.button}>Normal Button</button>
      <button className={`${styles.button} ${styles.primary}`}>Primary Button</button>
    </div>
  );
}

// MyComponent.module.css
.button {
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
}

.primary {
  background-color: palevioletred;
  color: white;
}