콘텐츠 대표 이미지 - CSS-in-JS, 너 혹시.. 내 프론트엔드 인생의 '치트키'니?

CSS-in-JS, 너 혹시.. 내 프론트엔드 인생의 '치트키'니?

스타일 가지고 고통받던 날들은 이제 안녕!
자바스크립트로 CSS를 가지고 노는 법, 지금부터 내가 아주 그냥 싹 다 알려줄게.
커피 한 잔 들고, 편하게 따라와 봐!

들어가며
"아, 이 CSS 또 어디서 꼬인 거야?!"

너, 혹시 이런 생각해 본 적 없어? 분명히 난 이 버튼 색깔을 파란색으로 바꿨는데, 왜 자꾸 빨간색이 나오는 거지? 개발자 도구를 열어보면 온갖 CSS 파일들이 서로 자기가 왕이라고 소리치고 있고, `!important`는 남발되어 있고... 아주 그냥 스타일시트가 아니라 전쟁터가 따로 없지.

특히 프로젝트 규모가 커지고, 여러 사람이 같이 작업하다 보면 CSS 관리는 정말 지옥 그 자체가 되곤 해. 클래스 이름 짓는 것부터가 고역이야. `card-button`, `main-card-button`, `user-profile-card-button`... 짓다 보면 현타가 오지. 이걸 해결하려고 BEM 같은 방법론도 나왔지만, 그것도 결국 사람이 하는 일이라 실수가 생기기 마련이거든.

그런데 말이야, 만약에...
우리가 가장 자신 있어 하는 자바스크립트(JavaScript)로 이 모든 CSS 문제를 해결할 수 있다면 어떨까?

클래스 이름 고민할 필요도 없고, 스타일이 다른 곳에 영향을 줄 걱정도 없고, 심지어 자바스크립트 변수나 상태(state)에 따라 스타일을 실시간으로, 아주 우아하게 바꿀 수 있다면?

이게 바로 오늘 우리가 깊게 파고들 주제, **CSS-in-JS**의 핵심이야. 말 그대로 '자바스크립트 안에 CSS를 작성하는' 기술이지. 처음엔 "굳이? CSS는 CSS 파일에 둬야지!"라며 저항감이 들 수도 있어. 나도 그랬거든. 하지만 한 번 맛보면 헤어 나올 수 없는 마성의 매력을 가졌다고!

이 글에서는 CSS-in-JS가 도대체 뭔지, 왜 우리 개발자들의 삶을 윤택하게 만들어주는지, 그리고 가장 핫한 라이브러리인 `styled-components`를 이용해서 어떻게 동적 스타일링을 구현하는지 A to Z까지 전부 다뤄볼 거야.

자, 이제 CSS와의 애증 관계를 청산하고, 자바스크립트와 찐한 연애를 시작할 준비, 됐어?

Chapter 1
CSS-in-JS, 개념부터 확실히 잡고 가자!

"CSS-in-JS? 그거 그냥 HTML 태그에 `style` 속성 넣는 거 아냐?" 라고 생각했다면, 반은 맞고 반은 틀려. 물론 그것도 넓은 의미에서는 자바스크립트로 스타일을 제어하는 거니까. 하지만 우리가 말하는 CSS-in-JS는 훨씬 더 체계적이고 강력한 패러다임을 의미해.

핵심은 이거야: **컴포넌트 기반 개발 환경에서 스타일을 컴포넌트의 일부로 포함시키는 것.**

React, Vue, Svelte 같은 모던 프론트엔드 라이브러리/프레임워크의 공통점이 뭔지 알아? 바로 '컴포넌트' 단위로 UI를 조립한다는 거야. 헤더, 버튼, 카드, 입력창... 모든 걸 독립적인 부품(컴포넌트)으로 만들지.

예전에는 구조는 HTML, 디자인은 CSS, 동작은 JS, 이렇게 파일을 분리하는 게 '관심사의 분리(Separation of Concerns)'라며 정석처럼 여겨졌어.

전통적인 웹 개발 vs 컴포넌트 기반 개발 전통적 방식 (관심사 분리) index.html (구조) style.css (디자인) script.js (동작) 컴포넌트 방식 (기능 분리) Button.jsx (구조+디자인+동작) Card.jsx (구조+디자인+동작) ... 패러다임의 전환

하지만 컴포넌트 시대에는 '관심사'의 기준이 바뀌었어. 이제는 '기능' 단위로 묶는 것이 새로운 '관심사의 분리'가 된 거야. '버튼'이라는 기능에 필요한 HTML 구조, CSS 디자인, JS 로직을 한 파일(`Button.jsx`)에 모아두는 거지. 이렇게 하면 버튼이 필요할 때마다 이 파일 하나만 가져다 쓰면 되니까 훨씬 편하고, 재사용성도 높아져.

CSS-in-JS는 바로 이 새로운 패러다임에 딱 들어맞는 방식이야. 컴포넌트에 필요한 스타일을 외부 CSS 파일이 아니라, 바로 그 컴포넌트 파일 안에서 자바스크립트로 정의해버리는 거지.

이게 왜 그렇게 좋냐고?

1. 완벽한 스타일 스코프(Scoped Styles) 보장

CSS-in-JS 라이브러리는 컴파일 과정에서 `a_1b2c3d` 처럼 절대 겹치지 않는 유니크한 클래스 이름을 자동으로 생성해줘. 그래서 내가 `Button` 컴포넌트에서 `.title` 이라는 스타일을 만들어도, 다른 `Card` 컴포넌트의 `.title` 과는 절대 충돌하지 않아. 전역 스코프 오염? 그게 뭐죠 먹는 건가요? 가 되는 거지. 더 이상 클래스 이름 짓느라 머리 싸맬 필요가 없어!

2. 진정한 동적 스타일링(Dynamic Styling)

이게 바로 CSS-in-JS의 꽃이야. 자바스크립트의 모든 힘을 스타일링에 그대로 쓸 수 있어. 컴포넌트가 받는 `props`, `state`, 또는 복잡한 함수 계산 결과에 따라 CSS 속성을 실시간으로 바꿀 수 있어. 예를 들어, `props.disabled`가 `true`이면 버튼을 회색으로, `false`이면 파란색으로 만드는 걸 삼항연산자 한 줄로 끝낼 수 있다는 거지. 기존 CSS로는 클래스를 여러 개 만들고 JS로 붙였다 떼었다 해야 했던 번거로운 작업이 사라져.

3. 쉬운 유지보수

스타일이 컴포넌트와 한 몸이니, 관리가 엄청나게 편해져. 특정 컴포넌트를 수정하거나 삭제할 때, 그 컴포넌트 파일만 보면 돼. 더 이상 "이 CSS 클래스, 지금 어디서 쓰고 있나?" 전전긍긍하며 전체 프로젝트를 검색할 필요가 없어. 컴포넌트를 지우면 그 스타일도 같이 사라지니까, 죽은 코드(Dead Code)가 남을 확률이 제로에 가까워져.

물론 처음에는 자바스크립트 파일에 CSS 코드가 들어가는 게 어색하게 느껴질 수 있어. 하지만 이건 단순히 파일을 합치는 게 아니라, **"스타일을 컴포넌트의 동적인 상태와 로직에 직접 연결한다"**는 개념의 전환으로 이해해야 해. 이 관점에서 보면, CSS-in-JS는 프론트엔드 개발의 복잡성을 해결해주는 아주 우아하고 강력한 도구인 셈이지.

Chapter 2
CSS-in-JS 라이브러리, 뭘 골라야 할까? (feat. 어벤져스)

CSS-in-JS의 세계에도 수많은 강자들이 존재해. 각자만의 철학과 장단점을 가지고 있지. 마치 어벤져스 멤버들처럼 말이야. 모든 상황에 완벽한 영웅은 없듯, 모든 프로젝트에 완벽한 라이브러리는 없어. 프로젝트의 성격과 팀의 스타일에 맞는 걸 고르는 게 중요해.

여기서는 가장 인기 있고, 각기 다른 개성을 가진 대표 주자 네 명을 소개해줄게.

1. styled-components: 인싸력 만렙, 우아함의 대명사

*별명: 아이언맨*
가장 대중적이고, 커뮤니티가 활발하며, 처음 보는 사람도 "오, 이거 좀 멋진데?" 하게 만드는 매력이 있어. 핵심 무기는 ES6의 **태그드 템플릿 리터럴(Tagged Template Literals)** 이야.

이게 뭐냐면, 백틱(`` ` ``)으로 감싼 문자열에 실제 CSS를 작성하듯 스타일을 넣을 수 있게 해주는 문법이야. 덕분에 자동완성이나 문법 하이라이팅 같은 IDE 지원도 빵빵하게 받을 수 있지.

styled-components 예시


import styled from 'styled-components';

// 'button' HTML 태그에 스타일을 입힌 새로운 리액트 컴포넌트 'Button'을 생성
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;
`;

// 사용법
// <Button>Default Button</Button>
// <Button primary>Primary Button</Button>
  

코드를 봐. 그냥 CSS 쓰듯이 자연스럽지 않아? `props`를 받아와서 조건부로 스타일을 바꾸는 부분도 직관적이야. React 생태계에서 가장 사랑받는 이유를 알겠지?

2. Emotion: 다재다능, 성능에 진심인 실력파

*별명: 캡틴 아메리카*
`styled-components`와 쌍벽을 이루는 라이브러리야. 기본적으로 매우 유사한 경험을 제공하지만, 몇 가지 차별점이 있어.

Emotion은 더 작고 빠르다고 알려져 있고, 프레임워크에 구애받지 않는(framework-agnostic) 것을 지향해. React 없이도 쓸 수 있다는 말이지. 또한, `styled-components`처럼 태그드 템플릿 리터럴 방식도 지원하고, CSS 속성을 자바스크립트 객체로 작성하는 방식도 지원해서 유연성이 높아.

Emotion (객체 스타일) 예시


import { css } from '@emotion/react';

const buttonStyle = css`
  color: hotpink;
`;

// 또는 객체로 작성
const buttonStyleObject = css({
  color: 'hotpink',
  fontSize: '1em'
});

// 사용법
// <div css={buttonStyle}>Hotpink Button</div>
  

`styled` API도 똑같이 제공해서 `styled-components`에서 넘어오기도 쉬워. 성능과 유연성을 중시한다면 Emotion은 훌륭한 선택이야.

3. JSS (JavaScript Style Sheets): 시대를 앞서간 원조 맛집

*별명: 닉 퓨리*
어벤져스를 결성한 닉 퓨리처럼, JSS는 CSS-in-JS 생태계의 기반을 닦은 대선배 격 라이브러리야. 이름 그대로, 스타일을 순수한 자바스크립트 객체(Object)로 정의하는 게 특징이지.

유명한 UI 라이브러리인 Material-UI(MUI)가 내부적으로 JSS를 사용하면서 더 널리 알려졌어. 플러그인 기반 아키텍처를 가지고 있어서 필요한 기능만 쏙쏙 골라 쓸 수 있는 확장성도 장점이야.

JSS 예시


import { createUseStyles } from 'react-jss';

const useStyles = createUseStyles({
  myButton: {
    backgroundColor: props => props.primary ? 'blue' : 'gray',
    color: '#fff',
    '&:hover': {
      backgroundColor: 'darkblue',
    }
  },
  myLabel: {
    fontWeight: 'bold'
  }
});

function MyComponent(props) {
  const classes = useStyles(props);
  return <button className={classes.myButton}>My Button</button>;
}
  

문법이 조금 달라 보이지? `useStyles`라는 훅을 만들고, 그 안에서 스타일 객체를 정의해. 컴포넌트 안에서는 이 훅을 호출해서 클래스 이름들을 받아와 `className`에 적용하는 방식이야. 자바스크립트에 더 친숙한 개발자라면 이 방식이 더 편하게 느껴질 수도 있어.

4. Stitches: 성능 끝판왕, 차세대 주자

*별명: 닥터 스트레인지*
가장 최근에 등장했지만, 혁신적인 기능으로 주목받고 있는 신성이야. Stitches의 가장 큰 특징은 **거의 제로 런타임(near-zero runtime)**을 지향한다는 거야.

대부분의 CSS-in-JS 라이브러리는 앱이 실행될 때(런타임) 자바스크립트가 스타일을 생성하고 DOM에 주입해. 이게 약간의 성능 저하를 유발할 수 있거든. 반면 Stitches는 가능한 많은 작업을 빌드 시점에 미리 처리해서 런타임 부하를 최소화해.

또 다른 킬링 포인트는 `variants` API야. 컴포넌트의 여러 가지 상태(variant)에 따른 스타일을 아주 깔끔하게 정의할 수 있게 해주지. 디자인 시스템을 구축할 때 특히 강력한 기능이야.

Stitches 예시


import { styled } from './stitches.config.js';

const Button = styled('button', {
  // 기본 스타일
  backgroundColor: 'gainsboro',
  borderRadius: '9999px',

  // Variants (상태에 따른 스타일 세트)
  variants: {
    color: {
      violet: { backgroundColor: 'blueviolet' },
      gray: { backgroundColor: 'gainsboro' },
    },
    size: {
      small: { padding: '8px 12px' },
      large: { padding: '12px 20px' },
    },
    outlined: {
      true: {
        backgroundColor: 'transparent',
        border: '2px solid currentColor'
      }
    }
  }
});

// 사용법
// <Button size="large" color="violet">Large Violet Button</Button>
// <Button outlined>Outlined Button</Button>
  

`variants`를 봐. `color`, `size`, `outlined` 같은 '속성'을 정의하고, 그 값에 따라 적용될 스타일을 미리 세팅해두는 거야. 코드가 훨씬 선언적이고 깔끔해지지?

자, 이렇게 네 명의 어벤져스를 만나봤어. 이 글에서는 가장 대중적이고 직관적인 **`styled-components`**를 메인으로 해서 동적 스타일링의 세계를 깊이 탐험해볼 거야. 아이언맨과 함께라면 두려울 게 없다고!

Chapter 3
실전! styled-components로 동적 스타일링 가지고 놀기

백문이 불여일견! 이제 이론은 잠시 접어두고, 직접 코드를 만져보면서 `styled-components`의 마법을 체험해 보자. React 프로젝트가 준비되어 있다고 가정하고 시작할게. (없다면 `npx create-react-app my-app`으로 후딱 하나 만들고, `cd my-app`으로 들어간 다음 `npm install styled-components` 또는 `yarn add styled-components`를 실행해 줘!)

3-1. 기본 중의 기본: Props로 스타일 제어하기

CSS-in-JS 동적 스타일링의 80%는 `props`를 활용하는 거야. 컴포넌트에 전달된 `props` 값에 따라 스타일을 다르게 적용하는 거지.

가장 흔한 예시, '기본 버튼'과 '주요 버튼'을 만들어보자. `primary`라는 `prop`이 `true`일 때만 다른 스타일을 적용해 볼 거야.

components/Button.js


import styled from 'styled-components';

// 1. styled.button`` 으로 button 태그에 대한 스타일 컴포넌트를 만든다.
const Button = styled.button`
  /* 기본 스타일: 모든 버튼에 공통으로 적용된다. */
  background: transparent;
  border-radius: 3px;
  border: 2px solid #3498db;
  color: #3498db;
  margin: 0.5em 1em;
  padding: 0.5em 1.5em;
  cursor: pointer;
  font-size: 1em;
  transition: all 0.2s ease-in-out;

  /* 2. props를 받아와서 조건부 스타일링을 적용한다. */
  /* props.primary가 true일 경우, 아래 CSS를 덮어쓴다. */
  ${props => props.primary && `
    background: #3498db;
    color: white;
  `}

  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 8px rgba(0,0,0,0.1);
  }
`;

export default Button;
  

App.js (사용하는 곳)


import Button from './components/Button';

function App() {
  return (
    <div>
      <h1>My Awesome Buttons</h1>
      {/* primary prop이 없으므로 기본 스타일 적용 */}
      <Button>Normal Button</Button>

      {/* primary={true} 이므로 조건부 스타일 적용 */}
      <Button primary>Primary Button</Button>
    </div>
  );
}

export default App;
  

어때? 정말 간단하지 않아?

`styled-components`의 템플릿 리터럴 안에서는 `${ }` 구문을 사용해서 자바스크립트 코드를 실행할 수 있어. 그 안으로 `props` 객체가 자동으로 전달되지. 우리는 `props.primary`가 `true`인지 확인하고, `true`라면 백틱으로 감싼 CSS 문자열을 반환했어. `false`라면 아무것도 반환하지 않으니, 기본 스타일만 남게 되는 원리야.

이런 식으로 `disabled`, `size`, `shape` 등 원하는 `prop`을 얼마든지 추가해서 다양한 베리에이션의 컴포넌트를 만들 수 있어.

예를 들어, `size` prop으로 버튼 크기를 조절해볼까?

components/Button.js (size prop 추가)


// ... (이전 Button 컴포넌트 코드)

// size prop에 따라 다른 padding과 font-size를 반환하는 함수
const getSizeStyles = (size) => {
  switch (size) {
    case 'small':
      return `
        font-size: 0.8em;
        padding: 0.4em 1em;
      `;
    case 'large':
      return `
        font-size: 1.2em;
        padding: 0.6em 2em;
      `;
    default: // 'medium' 또는 지정되지 않았을 때
      return `
        font-size: 1em;
        padding: 0.5em 1.5em;
      `;
  }
};

const Button = styled.button`
  /* ... (기본 스타일 및 primary 스타일) */
  
  /* getSizeStyles 함수를 호출하여 size에 맞는 스타일을 적용 */
  ${props => getSizeStyles(props.size)}
`;

// 사용법
// <Button size="small">Small</Button>
// <Button>Medium</Button>
// <Button size="large" primary>Large Primary</Button>
  

이렇게 스타일 로직이 복잡해질 것 같으면, 별도의 함수로 분리해서 가독성을 높일 수도 있어. 자바스크립트의 모든 문법을 활용할 수 있다는 게 바로 이런 점이야!

3-2. 테마(Theme)를 활용한 전역 스타일 관리

프로젝트를 하다 보면, 여러 컴포넌트에서 공통적으로 사용하는 색상, 폰트 크기, 간격 등이 있기 마련이야. 이걸 '디자인 토큰(Design Token)'이라고 부르는데, 이런 값들을 일관성 있게 관리하는 건 정말 중요해.

`styled-components`는 `ThemeProvider`라는 아주 강력한 기능을 제공해. 말 그대로, 우리 앱 전체에 '테마'를 입혀주는 컴포넌트야.

먼저, 우리 앱의 디자인 시스템을 정의하는 테마 객체를 만들어보자.

theme.js


// 우리 앱의 디자인 규칙을 담은 객체
export const theme = {
  colors: {
    primary: '#3498db',
    secondary: '#2ecc71',
    danger: '#e74c3c',
    light: '#f4f4f4',
    dark: '#222222',
  },
  fontSizes: {
    small: '0.8rem',
    medium: '1rem',
    large: '1.2rem',
  },
  spacing: {
    small: '8px',
    medium: '16px',
    large: '24px',
  },
  borderRadius: '4px',
};
  

이제 이 테마를 앱의 최상단에서 `ThemeProvider`로 감싸주기만 하면 돼. 보통 `index.js`나 `App.js`에서 처리하지.

index.js (또는 App.js)


import React from 'react';
import ReactDOM from 'react-dom/client';
import { ThemeProvider } from 'styled-components';
import { theme } from './theme'; // 방금 만든 테마 객체
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    {/* ThemeProvider로 App 전체를 감싼다 */}
    <ThemeProvider theme={theme}>
      <App />
    </ThemeProvider>
  </React.StrictMode>
);
  

준비는 끝났어! 이제 `ThemeProvider` 하위에 있는 모든 `styled-component` 안에서 `props.theme`을 통해 우리가 정의한 테마 객체에 접근할 수 있어.

아까 만들었던 버튼 컴포넌트를 테마를 사용하도록 리팩토링해볼까?

components/Button.js (테마 적용)


import styled from 'styled-components';

const Button = styled.button`
  /* 이제 하드코딩된 색상 대신 테마 값을 사용한다. */
  border-radius: ${props => props.theme.borderRadius};
  border: 2px solid ${props => props.theme.colors.primary};
  color: ${props => props.theme.colors.primary};
  margin: ${props => props.theme.spacing.small};
  padding: 0.5em 1.5em;
  cursor: pointer;
  font-size: ${props => props.theme.fontSizes.medium};
  transition: all 0.2s ease-in-out;

  ${props => props.primary && `
    background: ${props.theme.colors.primary};
    color: white;
  `}

  /* danger prop도 추가해볼까? */
  ${props => props.danger && `
    background: ${props.theme.colors.danger};
    border-color: ${props.theme.colors.danger};
    color: white;
  `}
`;

export default Button;
  

이제 우리 버튼은 더 이상 `#3498db` 같은 매직 넘버에 의존하지 않아. 오직 `theme.colors.primary` 라는 의미 있는 이름에만 의존하지. 만약 나중에 브랜드 메인 컬러를 바꿔야 한다면? `theme.js` 파일에서 딱 한 줄만 수정하면 앱 전체의 컬러가 한 번에 싹 바뀔 거야. 유지보수성이 엄청나게 올라가겠지?

다크 모드/라이트 모드 전환 같은 기능도 `ThemeProvider`를 활용하면 아주 쉽게 구현할 수 있어. 테마 객체를 두 개 만들어두고, 상태에 따라 `ThemeProvider`에 다른 테마를 주입해주기만 하면 되니까!

이런 체계적인 스타일 관리는 개인 프로젝트뿐만 아니라, 여러 개발자가 협업하는 팀 프로젝트에서 빛을 발해. 마치 재능 공유 플랫폼 **재능넷**에서 각 분야의 전문가들이 정해진 규칙 안에서 자신의 재능을 펼치듯, 개발자들도 잘 정의된 디자인 시스템 안에서 일관성 있고 효율적으로 UI를 개발할 수 있게 되는 거지.

3-3. 애니메이션과 상속: 스타일의 재활용

동적 스타일링이 어디 색깔 바꾸는 데만 쓰이겠어? 애니메이션도 얼마든지 동적으로 제어할 수 있어. `styled-components`는 CSS의 `@keyframes`를 만들 수 있는 `keyframes` 헬퍼를 제공해.

로딩 스피너를 한 번 만들어보자. 빙글빙글 돌아가는 간단한 애니메이션이야.

components/Spinner.js


import styled, { keyframes } from 'styled-components';

// 1. keyframes 헬퍼로 회전 애니메이션을 정의한다.
const rotate = keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
`;

// 2. 정의한 애니메이션을 컴포넌트에 적용한다.
const Spinner = styled.div`
  border: 4px solid ${props => props.theme.colors.light};
  border-top: 4px solid ${props => props.theme.colors.primary};
  border-radius: 50%;
  width: 40px;
  height: 40px;
  animation: ${rotate} 1s linear infinite;
`;

export default Spinner;
  

`keyframes`로 만든 `rotate` 애니메이션을 `animation` 속성에 그대로 넣어주면 끝! 정말 직관적이지.

이번엔 스타일 상속에 대해 알아보자. 이미 만들어둔 `Button` 컴포넌트의 스타일은 그대로 유지하면서, 몇 가지만 바꿔서 새로운 종류의 버튼을 만들고 싶을 때가 있어. 예를 들어, 링크(`` 태그)인데 버튼처럼 보이게 하고 싶을 때.

이럴 땐 `styled()` 괄호 안에 HTML 태그 이름 대신, 상속받고 싶은 다른 `styled-component`를 넣어주면 돼.

components/LinkButton.js


import styled from 'styled-components';
import Button from './Button'; // 우리가 만든 버튼 컴포넌트

// Button 컴포넌트의 모든 스타일을 상속받고,
// HTML 태그는 'a' 태그로 렌더링하면서 추가 스타일을 적용한다.
const LinkButton = styled(Button).attrs({ as: 'a' })`
  /* 추가하거나 덮어쓰고 싶은 스타일만 여기에 작성 */
  text-decoration: none;
  display: inline-block; /* a 태그는 기본이 inline이라 정렬을 위해 */

  /* 예를 들어, 보라색 테마의 링크 버튼을 만들어보자 */
  border-color: #8e44ad;
  color: #8e44ad;

  ${props => props.primary && `
    background: #8e44ad;
    border-color: #8e44ad;
    color: white;
  `}
`;

export default LinkButton;

// 사용법
// <LinkButton href="https://www.jaenung.net" target="_blank">
//   재능넷으로 이동
// </LinkButton>
  

`styled(Button)` 이렇게 하면 `Button`의 모든 스타일 규칙을 그대로 물려받아. 그리고 `.attrs({ as: 'a' })`는 이 컴포넌트가 최종적으로 렌더링될 때 `button` 태그가 아닌 `a` 태그로 렌더링되게 해주는 특별한 기능이야. 덕분에 `href` 같은 `a` 태그 전용 속성을 사용할 수 있게 되지.

이처럼 스타일을 상속하고 확장하는 기능을 활용하면, 코드 중복을 최소화하면서도 매우 유연하고 확장성 있는 컴포넌트 라이브러리를 구축할 수 있어.

Chapter 4
장점만 있을까? CSS-in-JS의 명과 암

지금까지 CSS-in-JS의 화려한 모습만 본 것 같아. 하지만 세상 모든 기술에는 장단점이 공존하는 법! 이 기술을 제대로 사용하려면, 어떤 트레이드오프가 있는지 명확히 알고 있어야 해.

CSS-in-JS의 장점(Pros)과 단점(Cons) 👍 장점 (Pros) ✅ 스타일 스코프: 클래스명 충돌 원천 봉쇄 ✅ 컴포넌트 중심: 스타일과 로직의 결합 ✅ 동적 스타일링: JS 변수/로직 직접 활용 ✅ 유지보수 용이: 컴포넌트 삭제 시 스타일도 함께 ✅ 벤더 프리픽스: 브라우저 호환성 자동 처리 ✅ 테마 기능: 일관된 디자인 시스템 구축 용이 ✅ 타입스크립트 지원: props 타입 추론으로 안정성 UP 👎 단점 (Cons) 🤔 런타임 오버헤드: JS 실행으로 스타일 생성 🤔 번들 사이즈 증가: 라이브러리 용량 추가 🤔 학습 곡선: 새로운 문법과 개념 필요 🤔 디버깅: 생성된 클래스명이 복잡해 추적 어려움 🤔 성능 민감성: 잦은 리렌더링 시 스타일 재계산 🤔 SSR/SSG 설정: 서버사이드 렌더링 시 추가 설정 필요 🤔 CSS 전문가와의 협업: JS 지식 필요

장점 (Pros) - 다시 한번 정리!

  • 진정한 컴포넌트화: 스타일까지 포함하여 컴포넌트를 완벽하게 독립적인 부품으로 만들 수 있어. 이식성과 재사용성이 극대화돼.

  • 개발 경험 향상: 클래스명 고민, 파일 간 이동, 스코프 걱정 등 자잘한 스트레스에서 해방돼. 개발자는 오직 컴포넌트의 로직과 스타일에만 집중할 수 있어.

  • 코드 관리의 용이성: 모든 것이 한곳에 모여있어(Colocation) 코드 파악이 쉽고, 컴포넌트를 삭제하면 관련된 모든 코드가 함께 사라져 프로젝트가 깨끗하게 유지돼.

단점 (Cons) - 솔직하게 짚고 넘어가자!

  • 런타임 성능 이슈: `styled-components` 같은 런타임 기반 라이브러리는 브라우저가 페이지를 그릴 때 자바스크립트를 실행해서 스타일 시트를 생성하고 DOM에 삽입해. 이 과정이 아주 약간의 성능 저하를 일으킬 수 있어. 특히 저사양 기기나 애니메이션이 많은 페이지에서는 체감될 수도 있지. (물론 대부분의 앱에서는 무시할 수 있는 수준이야. 그리고 Stitches나 Linaria 같은 제로 런타임 라이브러리들은 이 단점을 해결했지.)

  • 번들 사이즈: `styled-components` 라이브러리 자체의 용량이 우리 앱의 자바스크립트 번들 파일에 추가돼. 첫 페이지 로딩 속도에 민감한 서비스라면 고려해야 할 부분이야.

  • 디버깅의 어려움: 개발자 도구에서 엘리먼트를 살펴보면 `class="sc-a1b2c3d-0 kfLpRL"` 처럼 의미 없는 클래스 이름이 붙어있어. 물론 `styled-components`는 개발 모드에서 컴포넌트 이름을 클래스명에 포함시켜주긴 하지만, 전통적인 CSS 디버깅 방식보다는 조금 낯설 수 있어.

  • 러닝 커브: CSS와 자바스크립트에 모두 익숙해야 하고, 라이브러리 고유의 API와 동작 방식을 새로 배워야 해. 순수 CSS만 다루던 디자이너나 퍼블리셔와 협업할 때 장벽이 될 수도 있어.

결국 CSS-in-JS는 은탄환(Silver Bullet)이 아니야. 모든 문제를 해결해주는 만병통치약은 아니라는 거지. 하지만 **복잡하고, 동적이며, 수많은 컴포넌트로 이루어진 모던 웹 애플리케이션**을 만든다면, 단점보다는 장점이 훨씬 크다고 자신 있게 말할 수 있어.

마치며
그래서, CSS-in-JS 써야 돼, 말아야 돼?

오늘 우리는 CSS-in-JS의 세계를 함께 여행했어. 이게 왜 등장했는지부터 시작해서, 다양한 라이브러리들을 만나보고, `styled-components`를 이용해 직접 동적 스타일링을 구현하는 방법까지 깊숙이 파고들었지.

이제 너는 "CSS-in-JS 써야 하나?"라는 질문에 스스로 답을 내릴 수 있을 거야.

만약 네가...
- React, Vue 등 **컴포넌트 기반**으로 앱을 만들고 있고,
- 사용자의 인터랙션에 따라 **스타일이 실시간으로 바뀌는 기능**이 많고,
- 여러 명이 함께 작업하며 **일관된 디자인 시스템**을 유지해야 하고,
- CSS의 전역 스코프와 씨름하는 데 지쳤다면...


...그렇다면 **CSS-in-JS는 너의 개발 라이프를 한 단계 업그레이드시켜 줄 최고의 파트너**가 될 거야.

물론 간단한 정적 웹사이트나 개인 블로그를 만드는데 굳이 CSS-in-JS를 도입할 필요는 없을 수도 있어. 그럴 땐 순수 CSS나 Sass가 더 가볍고 빠른 선택일 수 있지. 언제나 그렇듯, 중요한 건 *'기술 그 자체'가 아니라 '상황에 맞는 도구를 선택하는 지혜'*니까.

하지만 오늘 배운 CSS-in-JS, 특히 동적 스타일링 기법은 현대 프론트엔드 개발자에게는 필수 교양과도 같아. 이 강력한 무기를 네 기술 스택에 추가해봐. 분명히 더 깔끔하고, 더 유지보수하기 쉽고, 더 다채로운 인터랙션을 가진 웹을 만들 수 있게 될 거야.

두려워하지 말고, 작은 토이 프로젝트부터 시작해봐. 직접 `props`로 색깔도 바꿔보고, `ThemeProvider`로 테마도 만들어보고, `keyframes`로 애니메이션도 넣어봐. 그 재미에 푹 빠지게 될 걸? 혹시 알아? 이 새로운 스킬로 **재능넷** 같은 곳에서 멋진 사이드 프로젝트를 시작하게 될지!

자, 이제 너의 코드가 자바스크립트의 힘으로 살아 움직이는 마법을 부릴 시간이야. Happy Coding!

댓글 작성

이 글에 대한 여러분의 생각을 들려주세요

댓글 0
댓글을 불러오는 중입니다.

아직 댓글이 없습니다.