[React] 스타일 라이브러리 styled-components stitches 비교

styled-components stitches 비교 예제

Posted by lim.Chuck on March 21, 2025

[React]

  1. [React] vite React설치
  2. Project initial setting
  3. Hooks && Library
    1. [React] Javascript 파일을 Typescript Import해보자
    2. [React] react-router-dom 알아보고 사용하자
    3. [React] child 컴포넌트에서 함수호출하기
    4. [React] useCallback
    5. [React] framer-motion 알아보고 사용하자
    6. [React] Context API
    7. [React] react lazy 지연로딩 예제
    8. [React] react에서 캐싱처리를 위한 react queryd와 indexDB 비교분석
    9. [React] 스타일 라이브러리 styled-components stitches 비교
  4. [React] 프론트 에러추적 도구 Sentry 사용해보기
  5. [React] React 19 주요 변경점
  6. [React] DOM이란 무엇이고? 가상 DOM이란 무엇인가?
  7. [React] preact 알아보기

🎨 styled-components vs Stitches: CSS-in-JS 라이브러리 비교

React 생태계에서 인기 있는 두 가지 CSS-in-JS 솔루션인 styled-components와 Stitches를 비교해보겠습니다. 이 두 라이브러리는 컴포넌트 기반 스타일링을 제공하지만, 접근 방식과 특징에서 중요한 차이가 있습니다.

📊 기본 특성 비교

특성 styled-components Stitches
📦 번들 크기 약 12-15KB (gzip) 약 5-8KB (gzip)
⚡ 성능 런타임 기반 사전 계산 가능한 원자적 CSS
🎯 동적 스타일링 런타임에 props 기반 변형(variants) 기반
🔍 TypeScript 지원 기본 지원 고급 타입 추론과 자동완성
🛠️ 테마 시스템 ThemeProvider createStitches 구성
📚 생태계 성숙도 매우 성숙함 비교적 새로움
🚀 SSR 지원 별도 설정 필요 기본 지원
🎭 개발 경험 자유로운 표현 구조화된 접근법

💻 기본 사용 예제 비교

styled-components 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import styled from "styled-components";

// 기본 스타일링
const Button = styled.button`
  background: ${(props) => (props.primary ? "blue" : "white")};
  color: ${(props) => (props.primary ? "white" : "blue")};
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid blue;
  border-radius: 3px;
`;

// 컴포넌트 확장
const BigButton = styled(Button)`
  font-size: 1.5em;
  padding: 0.5em 1.5em;
`;

function App() {
  return (
    <div>
      <Button>기본 버튼</Button>
      <Button primary>주요 버튼</Button>
      <BigButton>큰 버튼</BigButton>
    </div>
  );
}

Stitches 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import { styled, createStitches } from "@stitches/react";

// 테마 및 유틸리티 설정
const { css, theme } = createStitches({
  theme: {
    colors: {
      primary: "blue",
      text: "white",
    },
    space: {
      1: "0.25em",
      2: "0.5em",
      3: "1em",
    },
    fontSizes: {
      1: "1em",
      2: "1.5em",
    },
  },
});

// 스타일 정의
const Button = styled("button", {
  margin: "$3",
  padding: "$1 $3",
  fontSize: "$1",
  borderRadius: "3px",
  border: "2px solid blue",

  // 변형(variants) 정의
  variants: {
    variant: {
      primary: {
        background: "$primary",
        color: "$text",
      },
      secondary: {
        background: "white",
        color: "$primary",
      },
    },
    size: {
      normal: {},
      big: {
        fontSize: "$2",
        padding: "$2 $3",
      },
    },
  },

  // 기본값 설정
  defaultVariants: {
    variant: "secondary",
    size: "normal",
  },
});

function App() {
  return (
    <div>
      <Button>기본 버튼</Button>
      <Button variant="primary">주요 버튼</Button>
      <Button size="big">큰 버튼</Button>
      <Button variant="primary" size="big">
        큰 주요 버튼
      </Button>
    </div>
  );
}

🔑 주요 차이점 설명

1. 스타일링 접근법

styled-components:

  • 템플릿 리터럴을 사용한 CSS 작성
  • props에 기반한 동적 스타일링이 직관적
  • CSS-like 문법으로 전환이 쉬움

Stitches:

  • 객체 기반 스타일 정의
  • 사전 정의된 변형(variants) 시스템
  • 성능에 최적화된 접근법

2. 성능 특성

styled-components:

  • 런타임에 CSS 생성
  • 컴포넌트가 렌더링될 때마다 props 평가

Stitches:

  • 가능한 대부분의 CSS를 빌드 시간에 생성
  • 원자적 CSS 클래스 생성으로 CSS 중복 감소
  • 런타임 오버헤드 감소

3. 개발자 경험

styled-components:

  • 넓은 커뮤니티와 많은 예제
  • 직관적인 API
  • 대부분의 React 프로젝트에서 쉽게 통합

Stitches:

  • 강력한 TypeScript 통합
  • 변형 시스템을 통한 구조화된 디자인 시스템
  • 테마 토큰의 자동완성

📱 고급 기능 비교 예제

styled-components: 글로벌 스타일과 테마

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import { createGlobalStyle, ThemeProvider } from "styled-components";
import styled from "styled-components";

// 글로벌 스타일
const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
    padding: 0;
    font-family: 'Noto Sans KR', sans-serif;
    background-color: ${(props) => props.theme.background};
    color: ${(props) => props.theme.text};
  }
`;

// 테마 정의
const lightTheme = {
  background: "#ffffff",
  text: "#333333",
  primary: "#0070f3",
};

const darkTheme = {
  background: "#1a1a1a",
  text: "#f7f7f7",
  primary: "#3694ff",
};

// 테마에 의존하는 컴포넌트
const Card = styled.div`
  background-color: ${(props) => props.theme.background};
  color: ${(props) => props.theme.text};
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 8px;
  padding: 1rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`;

function App() {
  const [isDarkMode, setIsDarkMode] = useState(false);

  return (
    <ThemeProvider theme={isDarkMode ? darkTheme : lightTheme}>
      <GlobalStyle />
      <button onClick={() => setIsDarkMode(!isDarkMode)}>테마 전환</button>
      <Card>
        <h2>스타일된 카드</h2>
        <p>테마에 따라 스타일이 변경됩니다.</p>
      </Card>
    </ThemeProvider>
  );
}

Stitches: 테마 및 유틸리티

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { createStitches } from "@stitches/react";
import { useState } from "react";

// 스티치 설정
const { styled, createTheme, getCssText, globalCss } = createStitches({
  theme: {
    colors: {
      background: "#ffffff",
      text: "#333333",
      primary: "#0070f3",
      secondary: "#ff4081",
    },
    space: {
      1: "4px",
      2: "8px",
      3: "16px",
      4: "32px",
    },
    radii: {
      small: "4px",
      medium: "8px",
      large: "16px",
    },
    shadows: {
      small: "0 2px 4px rgba(0,0,0,0.1)",
      medium: "0 4px 8px rgba(0,0,0,0.1)",
    },
  },
  utils: {
    // 유틸리티 함수 정의
    marginX: (value) => ({
      marginLeft: value,
      marginRight: value,
    }),
    marginY: (value) => ({
      marginTop: value,
      marginBottom: value,
    }),
    paddingX: (value) => ({
      paddingLeft: value,
      paddingRight: value,
    }),
    paddingY: (value) => ({
      paddingTop: value,
      paddingBottom: value,
    }),
  },
});

// 다크 테마 정의
const darkTheme = createTheme({
  colors: {
    background: "#1a1a1a",
    text: "#f7f7f7",
    primary: "#3694ff",
    secondary: "#ff6b9d",
  },
});

// 글로벌 스타일
const globalStyles = globalCss({
  "body, html": {
    margin: 0,
    padding: 0,
    fontFamily: "'Noto Sans KR', sans-serif",
    backgroundColor: "$background",
    color: "$text",
  },
});

// 컴포넌트 정의
const Card = styled("div", {
  backgroundColor: "$background",
  color: "$text",
  border: "1px solid rgba(0, 0, 0, 0.1)",
  borderRadius: "$medium",
  padding: "$3",
  boxShadow: "$small",

  // 변형(variants) 정의
  variants: {
    type: {
      elevated: {
        boxShadow: "$medium",
      },
      flat: {
        boxShadow: "none",
      },
    },
    size: {
      small: {
        paddingX: "$2",
        paddingY: "$1",
      },
      large: {
        paddingX: "$4",
        paddingY: "$3",
      },
    },
  },
});

function App() {
  const [isDarkMode, setIsDarkMode] = useState(false);
  globalStyles();

  return (
    <div className={isDarkMode ? darkTheme : ""}>
      <button onClick={() => setIsDarkMode(!isDarkMode)}>테마 전환</button>
      <Card type="elevated">
        <h2>기본 카드</h2>
        <p>테마에 따라 스타일이 변경됩니다.</p>
      </Card>
      <Card type="flat" size="large">
        <h2>큰 플랫 카드</h2>
        <p>다양한 변형을 조합할 수 있습니다.</p>
      </Card>
    </div>
  );
}

⚖️ 장단점 요약

특성 styled-components Stitches
장점 🌐 넓은 커뮤니티와 생태계
📚 풍부한 학습 자료와 예제
🧩 React Native 지원
🎨 CSS와 유사한 문법으로 친숙함
🔄 props를 통한 유연한 동적 스타일링
⚡ 뛰어난 런타임 성능
📦 작은 번들 크기
💪 강력한 TypeScript 통합
🧱 변형 시스템을 통한 일관된 디자인 시스템
🛠️ 테마 토큰과 유틸리티 함수
단점 🐢 런타임 오버헤드로 인한 성능 제약
🏗️ 대규모 앱에서 번들 크기 증가
🔧 SSR 설정이 복잡할 수 있음
🧵 타입 안전성이 제한적
🌱 상대적으로 작은 커뮤니티와 생태계
📊 객체 기반 API가 CSS 개발자에게 덜 직관적
🧪 네이티브 지원 부족
🔄 동적 스타일링이 styled-components만큼 유연하지 않음

🎯 용도별 추천

사용 사례 추천 라이브러리 이유
대규모 엔터프라이즈 앱 Stitches 성능 최적화와 디자인 시스템 통합
빠른 프로토타이핑 styled-components 간편한 API와 친숙한 문법
디자인 시스템 개발 Stitches 변형과 테마 시스템의 강력한 지원
타입스크립트 프로젝트 Stitches 향상된 타입 안전성과 개발자 경험
소규모 팀/프로젝트 styled-components 낮은 학습 곡선과 풍부한 자료

CSS-in-JS 라이브러리를 선택할 때는 프로젝트 요구사항, 팀의 익숙함, 성능 고려사항을 종합적으로 평가하는 것이 중요합니다. styled-components는 더 성숙하고 직관적인 반면, Stitches는 성능과 타입 안전성에 초점을 맞춘 현대적인 대안을 제공합니다.