빌드 타임에 CSS를 정적으로 추출하는 Panda CSS를 1년 썼습니다. Tailwind·styled-components와 무엇이 어떻게 다른지, 모노레포 디자인 시스템에 쓸 때의 장단점과 효율적인 학습 순서를 정리했습니다.
프롤로그
프로젝트에서 Panda CSS를 도입해 사용해 보면서, 기존의 styled-components나 Tailwind CSS와는 다른 독특한 스타일 작성 방식을 체감할 수 있었습니다. 특히 TypeScript 기반의 타입 안전성, 빌드 타임에 CSS를 정적으로 추출하여 런타임 오버헤드를 줄이는 점, 그리고 CSS‑in‑JS 스타일 작성과 표준 CSS 문법을 모두 지원하는 유연함이 인상적이었습니다. 이번 글에서는 Panda CSS의 주요 기능, Tailwind 및 styled-components와의 차이점, 그리고 모노레포 환경에서 디자인 시스템으로 활용하는 방법에 대해 공유하고자 합니다.
1. Panda css의 주요 특징
빌드 타임 CSS 파일 생성
Panda CSS는 전통적인 CSS‑in‑JS 라이브러리와 달리, 런타임에 스타일을 동적으로 생성하지 않습니다. 빌드 타임에 AST 파싱과 스캐닝을 통해 소스 코드에서 유틸리티 클래스와 패턴을 추출하고, 이를 정적으로 CSS 파일로 생성합니다.
"유틸리티 클래스란 하나의 스타일 속성을 하나의 클래스로 정의하는 방식으로, 재사용성을 극대화하고 CSS 파일 크기를 최적화할 수 있는 접근법입니다. 빌드 타임 추출이란 애플리케이션이 실행되기 전, 코드를 분석하여 필요한 CSS만 미리 생성해놓는 기법으로, 런타임 성능을 향상시킵니다."
typescript
// panda.config.tsimport{ defineConfig }from'@pandacss/dev';exportdefaultdefineConfig({// 스타일 선언이 포함된 파일의 경로를 지정 include:['./src/**/*.{js,jsx,ts,tsx}','./pages/**/*.{js,jsx,ts,tsx}'],// 제외할 파일 경로 (필요한 경우) exclude:[],// 생성된 CSS 시스템 파일의 출력 디렉토리 outdir:'styled-system',// (선택) jsxFramework 옵션을 설정하여 JSX 패턴 지원 jsxFramework:'react',});
이 설정 파일은 Panda CSS가 프로젝트의 소스 코드를 스캔하여 사용된 스타일을 분석한 후, styled-system 폴더에 유틸리티 클래스들을 포함한 파일들을 생성하도록 합니다. 또한, 이후 생성된 CSS 파일을 앱에 import하여 사용할 수 있습니다.
이처럼 초기 설정(config 작성)과 스타일 추출 과정을 거치면, 런타임에는 미리 생성된 CSS 클래스가 적용되어 성능 최적화 효과를 누릴 수 있습니다.
2. TypeScript 기반 타입 안전성
Panda CSS는 처음부터 TypeScript를 염두에 두고 설계되었습니다.
token 설정 자동완성으로 사용이 가능 합니다.
tsx
// config.tsimport{ defineConfig }from'@pandacss/dev';exportdefaultdefineConfig({ theme:{// 👇🏻 Define your tokens here extend:{ tokens:{ colors:{ primary:{ value:'#0FEE0F'}, secondary:{ value:'#EE0F0F'},}, fonts:{ body:{ value:'system-ui, sans-serif'},},},},},});// App.tsximport{ css }from'../styled-system/css';functionApp(){return(<pclassName={css({ color:'primary', fontFamily:'body',})}> Hello World
</p>);}
Type safety참고 링크
Panda CSS는 타입 안전성을 보장하며 코드를 작성할 수 있습니다.
strictTokens 을 키게 되면
typescript
// 지정한 토큰 이외의 값을 사용 하면 타입 에러가 발생 하고 직접 값을 입력 하고 싶으면 []을 사용하면 됩니다.import{ css }from'../styled-system/css';css({ bg:'red'});// ❌ Error: "red" is not a valid token valuecss({ fontSize:'123px'});// ❌ Error: "123px" is not a valid token valuecss({ bg:'red.400'});// ✅ Validcss({ fontSize:'[123px]'});// ✅ Valid, since `[123px]` is using the escape-hatch syntaxcss({ content:'abc'});// ✅ Valid, since `content` isn't bound to a config token
또한 strictPropertyValues을 키게 되면
typescript
// 아래와 같이 없는 속성에 대한 타입 체크도 해주어 개발 편의성을 올려줍니다.css({ display:'flex'});// ✅ Validcss({ display:'block'});// ✅ Validcss({ display:'abc'});// ❌ will throw since 'abc' is not part of predefined values of 'display'css({ pos:'absolute123'});// ❌ will throw since 'absolute123' is not part of predefined values of 'position'css({ display:'[var(--btn-display)]'});// ✅ Valid, since `[var(--btn-display)]` is using the escape-hatch syntaxcss({ content:'""'});// ✅ Valid, since `content` does not have a predefined list of valuescss({ flex:'0 1'});// ✅ Valid, since `flex` does not have a predefined list of values
Variant 관리
Panda CSS의 cva 함수는 variant를 정의할 때 사용 가능한 옵션들을 자동으로 타입 추론해 주어, 컴포넌트 사용 시 안정적인 값만 입력되도록 도와줍니다.
표준 CSS 문법 사용
네이티브 CSS 네스팅 문법(예: &:hover { ... })을 사용할 수도 있으므로, 기존 CSS 문법에 익숙한 개발자도 자연스럽게 활용할 수 있습니다.
typescript
import{ css }from'../styled-system/css';// 표준 CSS 네스팅 방식 (native nesting 사용)const styleWithNesting =css({ bg:'green.400','&:hover':{ bg:'green.700',},});
3. Tailwind CSS 및 기존 styled-components와의 비교
Tailwind CSS
설정 파일의 TypeScript 지원
Tailwind는 tailwind.config.ts 파일을 통해 테마, 색상, 폰트 등 디자인 토큰을 타입 안전하게 관리할 수 있습니다. 하지만, 실제 마크업에 적용되는 유틸리티 클래스는 문자열로 작성되므로 타입 안전성이 내재되어 있지 않습니다.
추가 플러그인의 사용
Tailwind는 유틸리티 클래스가 문자열로 관리되어 가독성이 안 좋아 추가적인 플러그인 사용이 강제 됩니다.
반면 panda css는 미리 내장되어 있는 함수로 추가적인 설치 없이 사용이 가능 합니다.
이렇게 작성하면, 빌드 타임에 위의 스타일 객체가 자동으로 분석되어 원자 CSS 클래스들이 생성되고, 타입 안전성과 테마 토큰 연동 등도 자연스럽게 지원됩니다. 즉, variant와 관련된 로직을 별도로 설치할 필요 없이 Panda CSS 내부에서 바로 사용할 수 있습니다
ex) tailwind-variants
예를 들어, tailwind-variants를 사용한 경우는 아래와 같이 작성할 수 있습니다.
Tailwind CSS에서는 기본적으로 미리 만들어진 유틸리티 클래스를 조합하는 방식이 주를 이루지만, 위와 같이 플러그인을 도입하면 variant 시스템을 좀 더 체계적으로 관리할 수 있습니다. 다만, 이는 별도 설치 및 설정이 필요한 부분이며, Panda CSS의 cva는 처음부터 이러한 기능이 내장되어 있어 개발자가 추가 작업 없이 바로 사용할 수 있다는 점이 차별점입니다
styled-components
런타임 동적 스타일 생성
컴포넌트가 렌더링될 때마다 동적으로 CSS를 생성하여 DOM에 삽입합니다. 이 방식은 사용이 간편하지만, 매 렌더링 시 스타일 계산이 발생하며 SSR 환경에서 하이드레이션이 필요하고 청크 파일또한 증가하게 되어 성능에 이슈가 생길 수 있습니다.
Panda CSS는 다음과 같은 방식으로 모노레포 내 디자인 시스템 구성에 활용할 수 있습니다
공통 디자인 토큰 및 레시피 중앙 관리
Panda CSS의 panda.config.ts 파일에서 색상, 폰트, 간격 등의 디자인 토큰을 정의하고, 이를 레시피(예: 버튼, 텍스트 등)와 패턴으로 만들어 둡니다. 이 공통 디자인 시스템을 하나의 패키지로 구성하여, 모노레포 내 여러 프로젝트에서 재사용할 수 있습니다
1년 동안 Panda CSS를 사용하며, 타입 안전성을 비롯한 빌드 타임 CSS 추출, 재사용 가능한 레시피 및 패턴, 그리고 CSS‑in‑JS와 표준 CSS 문법의 유연한 혼용이라는 독특한 장점을 직접 체감할 수 있었습니다.
Tailwind CSS는 구성 파일에서는 TypeScript의 이점을 활용할 수 있으나, 실제 마크업에서 사용하는 유틸리티 클래스는 문자열 기반이어서 타입 안전성이 제한적입니다.
styled-components는 런타임 동적 스타일 생성 방식으로 편리하지만, 성능 및 SSR 측면에서 한계가 있습니다.
반면, Panda CSS는 전체 스타일링 워크플로우가 TypeScript와 긴밀하게 통합되어 있어, 대규모 프로젝트나 모노레포 환경에서 공통 디자인 시스템을 구성하고 유지보수하는 데 매우 유리합니다.
초기에는 “클래스가 미리 만들어진다”는 방식과 새로운 문법 체계가 다소 낯설게 느껴질 수 있으나, 장기적으로 보면 유지보수, 퍼포먼스, 협업 측면에서 큰 이점을 제공합니다.
특히 CSS-In-Js 문법을 좋아하는대 ssr과 성능 최적화를 챙기고 싶으신 분이라면 panda css는 좋은 대안이 될 것이라고 생각 합니다.